1. Related concepts

  • Program: A collection of instructions, a static piece of code.

  • 1. A running program, a dynamic process; It has its own life cycle and is a unit of resource allocation (the system allocates a different area of memory to each process).

  • Thread: A further refinement of a process, a path of execution within a program.

2. Create a thread

2.1 inheritance Thread

Declare a class that inherits Thread and override the run() method

public class MyThread extends Thread {
    @Override
    public void run(a) {
        for (int i = 0; i < 100; i++) {
            if (i % 2= =0) { System.out.println(i); }}}}Copy the code

2. Create an instance object of the class and call the start() method

public class Test {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        // If run() is called, it is just a normal method call and no new thread is createdt1.start(); }}Copy the code

2.2 implement Runnable

Declare a class that implements the Runnable interface and override the run() method

public class MyThread2 implements Runnable {
    @Override
    public void run(a) {
        for (int i = 0; i < 100; i++) {
            if (i % 2= =0) { System.out.println(i); }}}}Copy the code

Create an instance of the class, pass it as an argument to the Thread constructor, and call the start() method of the Thread object

public class Test2 {
    public static void main(String[] args) {
        MyThread2 t2 = new MyThread2();
        newThread(t2).start(); }}Copy the code

2.3 implement Callable

1. Declare a class that implements the Callable interface and override the Call () method

public class MyThread3 implements Callable {
    @Override
    public Object call(a) throws Exception {
        int sum = 0;
        for (int i = 0; i < 100; i++) {
            if (i % 2= =0) { System.out.println(i); sum += i; }}returnsum; }}Copy the code

2. Create an instance of the class, pass it as a parameter to the FutureTask constructor, pass the FutureTask object to the Thread constructor, and call start() on the Thread object. If you need to get the return value of call(), the Get () method of the FutureTask object is called

public class Test3 {
    public static void main(String[] args) {
        MyThread3 t = new MyThread3();
        FutureTask ft = new FutureTask(t);
        new Thread(ft).start();
        try {
            The return value of get() is the return value of call() of the Callable instance object in the FutureTask constructor
            Object sum = ft.get();
            System.out.println(sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch(ExecutionException e) { e.printStackTrace(); }}}Copy the code

2.4 Using thread pools

1. Declare a class that implements the Runnable or Callable interface, like MyThread2 or MyThread3 above

Create the ExecutorService object, and call its execute() or submit() methods

public class Test4 {
    public static void main(String[] args) {
        // Create a thread pool
        ExecutorService service = Executors.newFixedThreadPool(10);

// Set the various properties of the thread pool
// ThreadPoolExecutor newService = (ThreadPoolExecutor) service;
// newService.setXXX();

        service.execute(new MyThread2()); // Objects suitable for implementing Runnable
// service.submit(new MyThread3()); Objects suitable for implementing Callable

        // Close the thread poolservice.shutdown(); }}Copy the code

3. Common methods of Thread

methods role
void start() Start the thread and call the run() method
void run() If the thread is constructed using a separate Runnable run object, the Runnable object’s run method is called. Otherwise, the method does nothing and returns
Thread currentThread() Gets the thread currently executing
String getName() Gets the name of the current thread
void setName(String name) Sets the name of the current thread
void yield() Suspends the currently executing thread object and executes the other threads
void join() Wait for the current thread to complete. For example, if thread A calls thread B’s join(), thread A blocks until thread B finishes executing
void stop() (Has been out of date) forces the current thread to terminate
void sleep(long millis) Let the thread sleep millis for milliseconds
boolean isAlive() Determines whether the thread is active

4. Thread priority

4.1 Three Basic priorities

1. MAX_PRIORITY: 10

2. NORM_PRIORITY: 5

3. MIN_PRIORITY: 1

A high-priority thread preempts a low-priority thread’s CPU execution, but only on a probabilistic basis. It does not mean that the low-priority thread executes only when the high-priority thread finishes.

4.2 Related Methods

methods role
int getPriority() Gets the priority of the thread
void setPriority(int newPriority) Change the thread priority

5. Thread lifecycle

The life cycle of a thread is roughly as follows:

6. Synchronize threads

6.1 Thread safety Issues

Thread insecurity occurs when multiple threads operate on a shared resource. Here’s an example.

6.2 Examples of Thread Insecurity

Mimicking the way ticket stations sell tickets.

1, create a ticket station, a total of 10 tickets

public class Station implements Runnable {
    private int ticket = 10;
    @Override
    public void run(a) {
        while (true) {
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + ":" + ticket);
                ticket--;
            } else {
                break; }}}}Copy the code

2. Create three Windows to sell tickets. These 10 tickets are shared resources

public class Test {
    public static void main(String[] args) {
        Station s = new Station();
        Thread t1 = new Thread(s);
        Thread t2 = new Thread(s);
        Thread t3 = new Thread(s);
        t1.setName("Window 1");
        t2.setName("Window 2");
        t3.setName("Window 3"); t1.start(); t2.start(); t3.start(); }}Copy the code

3. Analysis results

The following output is displayed

Window 1:10 window 2:10 window 1:9 window 2:8 window 1:7 window 2:6 window 1:5 window 1:2 window 1:1 window 3:4 window 2:4Copy the code

Although the result of each run is different, there is a high probability that multiple Windows will sell the same ticket, which is obviously unreasonable and unsafe for threads.

6.3 Addressing thread Insecurity

6.3.1 Synchronizing Code Blocks

1. Preparation of synchronized code blocks

synchronized (mutex) {
    // Code for manipulating shared resources
}
// mutex: Synchronization monitor (lock). Any object can act as a synchronization monitor, but the threads must share the same monitor.
Copy the code

2. Modify the Station class of the above example

public class Station implements Runnable{
    private int ticket = 10;
    Object mutex = new Object();
    @Override
    public void run(a) {
        while (true) {
            synchronized (mutex) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + ":" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}
Copy the code

3. The running result after modification is as follows

Window 2:10 window 2:9 window 2:8 window 2:7 window 2:6 window 2:5 window 2:4 window 3:3 window 3:2 window 1Copy the code

No matter how many times you run it, there will never be multiple Windows selling the same ticket.

6.3.2 Synchronization method

1. Encapsulate the code that operates on shared resources into a method and modify that method with synchronized

public class Station implements Runnable{
    private int ticket = 10;
    @Override
    public void run(a) {
        while (true) {
            boolean flag = sell();
            if(! flag) {break; }}}private synchronized boolean sell(a) { // The synchronization monitor is this keyword
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + ":" + ticket);
            ticket--;
            return true;
        }
        return false; }}Copy the code

2. The operation result after modification is also reasonable and safe

3. Precautions

  • The synchronization monitor for non-statically synchronized methods is this
  • The synchronization monitor for a statically synchronized method is the owning class itself, xxx.class

6.3.3 Lock Lock

ReentrantLock, an implementation class that uses the Lock interface, also addresses thread insecurity. The following code

public class Station implements Runnable{
    private int ticket = 10;
    private ReentrantLock lock = new ReentrantLock();
    @Override
    public void run(a) {
        while (true) {
            try {
                / / lock
                lock.lock();
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + ":" + ticket);
                    ticket--;
                } else {
                    break; }}finally {
                / / unlocklock.unlock(); }}}}Copy the code

(Note: Manual locking and unlocking is required to use Lock)

7. Thread communication

Thread communication in this article can be understood as regular access to shared resources between threads. In the thread-safe example above, threads always acquire CPU execution at random, resulting in inconsistent results from each run. So there are a couple of things we can do to create some sort of pattern between threads. For example, if there is a need for two threads to output between 1 and 100 in turn, we can do this:

7.1 Writing the Number Class

public class Number implements Runnable {
    private int num = 1;
    private Object obj = new Object();
    @Override
    public void run(a) {
        while (true) {
            synchronized (obj) {
                obj.notify(); // Wake up threads that have entered wait()
                if (num <= 100) {
                    System.out.println(Thread.currentThread().getName() + ":" + num);
                    num++;
                    try {
                        obj.wait(); // The current thread blocks until another thread calls notify() of the monitor
                    } catch(InterruptedException e) { e.printStackTrace(); }}else {
                    break;
                }
            }
        }
    }
}
Copy the code

7.2 Writing test Classes

public class Test02 {
    public static void main(String[] args) {
        Number n = new Number();
        Thread t1 = new Thread(n);
        Thread t2 = new Thread(n);
        t1.setName(Thread 1 "");
        t2.setName(Thread 2 ""); t1.start(); t2.start(); }}Copy the code

7.3 Output Results

Thread 1:1 thread 2:2 thread 1:3 thread 2:4 thread 1:5 thread 2:6 thread 1:7 thread 2:8 thread 1:9 thread 2:10......Copy the code

7.4 Related methods

methods role
void wait() The current thread blocks until another thread calls the notify() method of the monitor
void notify() Wake up the threads that entered wait(), or if there are more than one, by priority
void notifyAll() Wake up all threads that have entered wait()

Matters needing attention

  • These three methods are used in synchronized code blocks or synchronized methods
  • The callers of these three methods must be synchronization monitors. In the example above, the OBj object is the monitor, so it is invoked by it
  • Since any Object can be a synchronization monitor, and the callers of these three methods must be monitors, these three methods are actually declared in the Object class

7.5 Comparison of sleep() and Wait ()

Similarities:

  • Can cause the current thread to block

Difference:

  • Sleep () is declared in Thread and wait() in Object
  • Depending on the call scenario, sleep() can be used in any scenario, while wait() is used in synchronized code blocks or synchronized methods
  • Sleep () does not release the synchronization monitor (lock), while wait() does

8. Producer/consumer issues

The requirements are as follows: the maximum number of a product is 20. When the number of products is greater than 0, consumers can consume. When the number of products is less than 20, the producer can produce.

1. Write product classes

public class Product {
    private int num = 0;
    public synchronized void addProduct(a) {
        if (num < 20) {
            System.out.println(Thread.currentThread().getName() + "Produce the product");
            num++;
            System.out.println("Existing Product" + num + "个");
            System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
            notify();
        } else {
            try {
                wait();
            } catch(InterruptedException e) { e.printStackTrace(); }}}public synchronized void delProduct(a) {
        if (num > 0) {
            System.out.println(Thread.currentThread().getName() + "Consumer products");
            num--;
            System.out.println("Existing Product" + num + "个");
            System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
            notify();
        } else {
            try {
                wait();
            } catch(InterruptedException e) { e.printStackTrace(); }}}}Copy the code

2. Write the producer class

public class Producer extends Thread {
    private Product product;
    @Override
    public void run(a) {
        while (true) {
            try {
                sleep(10);
            } catch(InterruptedException e) { e.printStackTrace(); } product.addProduct(); }}public Producer(Product product) {
        super(a);this.product = product; }}Copy the code

3. Write the consumer class

public class Consumer extends Thread {
    private Product product;
    @Override
    public void run(a) {
        while (true) {
            try {
                sleep(10);
            } catch(InterruptedException e) { e.printStackTrace(); } product.delProduct(); }}public Consumer(Product product) {
        super(a);this.product = product; }}Copy the code

4. Write test classes

public class Test {
    public static void main(String[] args) {
        Product p = new Product();
        Producer producer = new Producer(p);
        Consumer consumer = new Consumer(p);

        producer.setName("Producer");
        consumer.setName("Consumer"); producer.start(); consumer.start(); }}Copy the code

5. The running results are as follows

Producers to produce the product Existing products 1 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- consumer products Existing products zero -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- producer production products An existing product -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- consumer products Existing products zero -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --...Copy the code

9. Related links

  • The resources