Brother Qiang said Java--Java multithreading

Posted by viv on Wed, 24 Nov 2021 08:02:24 +0100

preface

This article refers to the Silicon Valley Java tutorial
Continue to update the Java advanced section in the future

General catalogue

1, Basic concepts

1. Procedure

It is a set of instructions written in a certain language to complete characteristic tasks. That is, static code, static objects

2. Process

A process is an execution of a program, or a running program. It is a dynamic process with its own process of emergence, existence and extinction - life cycle

Such as QQ in operation and LOL in operation

The program is static and the process is dynamic

Process is the unit of resource allocation. The system will allocate different memory areas for each process at run time

3. Thread

A process can be subdivided into threads, which is an execution path within a program

If a process executes multiple threads in parallel at the same time, it supports multithreading

Thread is the unit of scheduling and execution. Each thread uses an independent running stack and program counter (pc). The overhead of thread switching is small

Multiple threads in a process share the same memory unit / memory address space. They allocate objects from the same heap and can access the same variables and objects. This makes the communication between threads easier and more efficient. However, system resources shared by multiple threads may bring security risks

Memory structure of JVM virtual machine

3. Case understanding

The above figure shows the processes running on my computer. The running software (a set of instructions written to complete characteristic tasks) is a process (an execution process of the program). For example, my IDEA can open multiple windows, that is, the IDEA supports threads (an execution path inside the program)

4. Understanding of single core CPU and multi-core CPU

Single core CPU is a fake multithreading. In a time unit, only one thread can be executed, but the CPU runs faster and can't feel it.

If it is multi-core, it can give better play to the efficiency of multithreading. (today's servers are multi-core)

A Java application java.exe actually has at least three threads: Main () main thread, gc () garbage collection thread and exception handling thread

5. Parallelism and concurrency

Parallel: multiple CPU s execute multiple tasks at the same time. For example, many people do different things at the same time.
Concurrency: one CPU (using time slice) executes multiple tasks at the same time. For example: Double 11 second kill, multiple people do the same thing.

6. Advantages of using multithreading

1. Improve application response. It is more interesting for the graphical interface and can enhance the user experience

2. Improve CPU utilization of computer system

3. Improve the program structure. The long and complex process is divided into multiple threads, which is allowed in the calf, which is conducive to understanding and modification

7. When multithreading is required

The program needs to perform two or more tasks at the same time

The program needs to be implemented -- when some tasks need to wait, such as user input, file read-write operation, network operation, search, etc

When you need some programs running in the background

2, Creation and use of threads

The JVM of the Java language allows programs to run multiple threads, which is embodied by the java.lang.Thread class.

1. Characteristics of thread class

Each Thread completes its operation through the run() method of a specific Thread object. The body of the run() method is often called the Thread body

Start the Thread through the start() method of the Thread object instead of directly calling run()

2.Thread class

constructor

Thread(): creates a new thread object

Thread(String threadname): create a thread and specify the thread instance name

Thread(Runnable target): Specifies the target object to create the thread, which implements the run method in the Runnable interface

Thread(Runnable target, String name): creates a new thread object

3. There are two ways to create threads in API

There are two ways to create a new execution thread before JDK15:

How to inherit the Thread class
How to implement the Runnable interface

Method 1: inherit Thread class

1) Defines subclasses that inherit the Thread class
2) Override the run method in the Thread class in the subclass.
3) Create a Thread subclass object, that is, create a Thread object.
4) Call the thread object start method: start the thread and call the run method.

package com.example.www.d4;

/**
 * @ClassName ThreadTest
 * @Description Multithreading practice
 * @Author Jack
 * @Date 2021/11/21 20:58
 * @Version 1.0
 */

/**
 * Multi Thread creation: Method 1: inherit from Thread class
 * 1,Create a subclass that inherits the Thread class
 * 2,Override the run () method of the tree class -- > declare the operation performed by this thread in the method body
 * 3,An object that creates a subclass of the Thread class
 * 4,start() is called from this object
 * <p>
 * Example: traverse all even numbers within 100
 */

//1. Create a subclass that inherits Thread class
class MyThread extends Thread {
    //2. Rewrite the run method
    @Override
    public void run() {
        for (int i = 0; i < 101; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        //3. Create objects of subclasses of Thread class
        MyThread t1 = new MyThread();
        //4. Call start() through this object
        t1.start();//Cause this thread to start execution; The Java virtual machine calls the run method of this thread.
        //Problem 1: we can't start the thread by calling the run method
//        myThread.run(); // No new threads will be started
        //Problem 2: start another thread and traverse an even number within 100. You can't let the thread that has started () execute. An illegalThread exception will be reported


        //We need to recreate a Thread object, that is, recreate an object of Thread subclass

        MyThread t2 = new MyThread();
        t2.start();


        //The following operations are still performed in the main thread
        for (int i = 0; i < 101; i++) {
            if (i % 2 != 0) {
                System.out.println(Thread.currentThread().getName() + "" + "**********hello********");
            }
        }

    }
}

The implementation is as follows:

Attention

1. If you call the run() method manually, it's just a normal method and does not start the multithreading mode.

2. The run () method is called by the JVM. When it is called and the process control executed are determined by the CPU scheduling of the operating system.

3. To start multithreading, you must call the start method.

4. A thread object can only call the start() method once to start. If it is called repeatedly, the above exception "lllgalThreadStateException" will be thrown

Method 2: implement Runnable interface

1) Defines the implementation class of the Runnable interface

2) Reproduce the run method of the interface

3) Create subclass objects

4) Pass a subclass object into the constructor of the Thread class

5) Start the Thread by calling the start method through the Thread, and call the run method in the Runnable implementation class

package com.example.www.d4;

/**
 * @ClassName ThreadTest1
 * @Description The second way to create multithreading is to implement the Runnable interface
 * 1.Create a class that implements the Runnable interface
 * 2.The implementation class implements the abstract method in Runnable: run()
 * 3.Create an object that implements the class
 * 4.Pass this object as a parameter to the constructor of the Thread class to create an object of the Thread class
 * 5.Call start() to start the current thread, and call run() of the current thread
 * @Author Jack
 * @Date 2021/11/22 7:27
 * @Version 1.0
 */

//1. Create an implementation class
class MyThread3 implements Runnable{
    //2. Implement the abstract method in Runnable
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

public class ThreadTest1 {
    public static void main(String[] args) {
        //3. Create an object that implements the class
        MyThread3 t3 = new MyThread3();
        //4. Pass this object as a parameter to the construction method of Thread
        Thread t = new Thread(t3);
        //5. start the Thread through the object of Thread class, call the run -- > of the current Thread, and call the target of Runnable type
        t.start();
    }
}

4. Connection and difference between inheritance and Realization

public class Thread extends Object implements Runnable

difference

Inherit Thread: Thread code is stored in the run method of Thread subclass.
Implementation of Runnable: the thread code has the run method of the implementation class of the interface.

Benefits of implementation

The limitation of single inheritance is avoided
Multiple threads can share the object of the same interface implementation class, which is very suitable for multiple same threads to process the same resource.

5. Related methods of thread class

void start(): starts the thread and executes the run() method of the object

run(): the operation performed by the thread when it is scheduled

String getName(): returns the name of the thread

void setName(String name): sets the thread name

static Thread currentThread(): returns the current Thread. this is in the Thread subclass, which is usually used for the main Thread and Runnable implementation class

static void yield(): thread yield

Pause the thread currently executing and give the execution opportunity to the thread with the same or higher priority

If there are no threads with the same priority in the queue, this method is ignored

**join() 😗* When the join () method of other threads is invoked in a program execution stream, the calling thread will be blocked until the join thread added by the join () method is executed.

static void sleep(long millis): (specified time: ms)

Make the current active thread give up control over the CPU within the specified time period, so that other threads have the opportunity to be executed, and re queue when the time comes.
Throw InterruptedException exception

stop(): force the end of the thread lifetime. It is not recommended

boolean isAlive(): returns boolean to judge whether the thread is still alive

Java scheduling method

Threads with the same priority form a first in first out queue (first in first out service) and use the time slice strategy
For high priority, the preemptive strategy of priority scheduling is used

Priority level of the thread

​ MAX_ PRIORITY: 10
​ MIN_ PRIORITY: 1
​ NORM_ PRIORITY: 5

Methods involved

getPriority(): returns the thread priority value
setPriority(int newPriority): change the priority of the thread

explain

When a thread is created, it inherits the priority of the parent thread
Low priority only has a low probability of obtaining scheduling, and is not necessarily called after high priority threads

package com.example.www.d4;

/**
 * @ClassName ThreadMethodTest
 * @Description Thread Common methods of
 * 1.start(): Start the current thread and call run() of the current thread
 * 2.run(): You usually need to override this method in the Thread class to write the operation to be performed by the Thread creation
 * 3.currentThread: Static method that returns the thread of the current code
 * 4.getName()Gets the name of the current thread
 * 5.setName Sets the name of the current thread
 * 6.yield(): Release current cpu execution rights
 * 7.join(): Call thread b join in thread a. At this point, thread a enters a blocking state until thread b completes, and thread a ends blocking state.
 * 8.stop()Obsolete. When this method is executed, the current thread is forced to end
 * 9.sleep(long milltime):Let the current thread sleep for the specified millitime milliseconds. Within the specified time, the thread is in a blocked state
 * 10.isAlive()Determine whether the thread is alive
 * <p>
 * <p>
 * thread priority 
 * 1.
 * MAX_PRIORITY 10
 * MIN_PRIORITY 1
 * NORM_PRIORITRY 5
 * 2.How to get and set the priority of the current thread
 * getPriority():Gets the priority of the thread
 * setPriority():Set thread priority
 * @Author Jack
 * @Date 2021/11/21 22:14
 * @Version 1.0
 */


public class ThreadMethodTest {


    public static void main(String[] args) {
        MyThread2 t1 = new MyThread2();

        t1.setName("Thread 1");

        //Set the priority of threads
        t1.setPriority(Thread.MAX_PRIORITY);
        t1.start();

        Thread.currentThread().setName("Main thread");
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
        for (int i = 1; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i);
//            if (i % 20 ==0){
//                try {
//                    t1.join();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
        }
        System.out.println(t1.isAlive());
    }


}

class MyThread2 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
//                try {
//                    sleep(20);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                System.out.println(Thread.currentThread().getName() + ":" + getPriority() + ":" + i);
            }
//            if (i == 20) {
//                yield();// Release the execution rights of the current cpu
            //Thread 1:80
            //Main thread: 75
            //... when thread 1 releases the execution right of the current cpu, other threads will rob
//            }
        }
    }
}

6. Classification of threads

Threads in Java are divided into two categories: one is daemon thread and the other is user thread.

They are the same in almost every way, and the only difference is to judge when the JVM leaves.
Daemon threads are used to serve user threads. By calling thread.setDaemon(true) before the start() method, a user thread can be turned into a daemon thread.
Java garbage collection is a typical daemon thread.
If there are daemon threads in the JVM, the current JVM will exit.
Image understanding: the rabbit dies and the dog cooks, and the birds hide

When the birds are gone, the bow will be hidden; After the rabbits were killed, the hounds were useless and cooked.

7. Thread life cycle

NEW

Runnable

Blocked

Waiting

Timed_waiting

Terminated

To implement multithreading, you must create a new Thread object in the main Thread. The Java language uses the objects of Thread class and its subclasses to represent threads. In a complete life cycle, it usually experiences the following five states:

New: when the object of a Thread class or its subclass is declared and created, the new Thread object is in the new state
state
Ready: after the thread in the new state is started (), it will enter the thread queue and wait for the CPU time slice. At this time, it has been started
The conditions for operation are met, but the CPU resources are not allocated
Run: when the ready thread is scheduled and obtains CPU resources, it enters the running state, and the run() method defines the line
Operation and function of the process
Blocking: in a special case, when the input / output operation is suspended or executed artificially, the CPU is released and temporarily suspended
Stop your own execution and enter the blocking state
Dead: the thread has completed all its work, or the thread is forcibly suspended in advance or terminated due to an exception

3, Thread synchronization

When multiple threads operate and share data together, the operation will be incomplete and the data will be destroyed

When multiple threads operate to share data, one thread only executes part of the statements, and the other thread also participates. Can cause errors in shared data

The code is as follows:

package com.example.www.d4;

/**
 * @ClassName WindowTest
 * @Description Selling tickets
 * Example: create three windows to sell tickets, and the total number of tickets is 100
 * There is now a thread security issue
 * @Author Jack
 * @Date 2021/11/21 23:33
 * @Version 1.0
 */
public class WindowTest {
    public static void main(String[] args) {
        Window w1 = new Window();
        Window w2 = new Window();
        Window w3 = new Window();

        w1.setName("Window one");
        w2.setName("Window II");
        w3.setName("Window three");
        w1.start();
        w2.start();
        w3.start();
    }
}

class Window extends Thread {
    private static int ticket = 100;
//    private static Object obj =new Object();

    @Override
    public void run() {
        while (true) {
//            synchronized (Window.class){
                if (ticket > 0) {
                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName() + ":Ticket number" + ticket);
                    ticket--;
                }else {
                    break;
                }
//            }

        }
    }
}


The output result is:
...
...
Window three:Ticket No. 13
 Window II:Ticket No. 13
 Window one:Ticket No. 13
 Window one:Ticket No. 10
 Window three:Ticket No. 10
 Window II:Ticket No. 8
 Window three:Ticket No. 7
 Window one:Ticket No. 6
 Window II:Ticket No. 5
 Window three:Ticket No. 4
 Window II:Ticket No. 4
 Window one:Ticket No. 4
 Window three:Ticket number 1
 Window II:Selling tickets, ticket number 0
 Window one:Ticket number-1

resolvent:

When a thread operates on shared data, it cannot continue until it has finished operating on other threads

1. Usage of synchronized

Java provides a professional solution to this problem: synchronization mechanism

Understanding synchronization and asynchrony

Synchronous and asynchronous focus on message communication mechanisms

Synchronization is to call something. The caller has to wait for the return result of the call before continuing to execute later. Asynchrony and synchronization, the caller will not wait for the result, but after the call is issued, the caller can continue to perform subsequent operations. Which call will be processed first?

Synchronous and asynchronous, for example, five guests come to a restaurant. Synchronous means that the first one to order dishes and order a fish. OK, the chef goes to catch and kill fish. After half an hour, the fish is ready for the first guest and the next guest. Come one by one in this order

Similarly, asynchrony means to come to the first guest, order something, order fish, give it a brand and let him wait. The next guest then orders, and after ordering, let the cook do it. Whichever dish is good first comes out first,

The advantages of synchronization are: synchronization is carried out one by one in order, which will not be disordered, and the following code will not be executed before the above code is executed. The disadvantages are: the parsing speed is not as fast as asynchronous;

The advantages of asynchrony are: asynchrony is to take a task and directly give it to the background. It has always been like this before taking the next task. Who reads it first and executes it first. Disadvantages: there is no order. Who reads it first and executes it first will appear that the above code has already come out before the following code comes out, and an error will be reported;

1. Synchronization code block:
synchronized (object){
//Code to be synchronized;

2.synchronized can also be placed in the method declaration, indicating that the whole method is a synchronous method.

For example:
public synchronized void show (String name){
}

The implementation is as follows

package com.example.www.d4;

/**
 * @ClassName WindowTest
 * @Description Selling tickets
 * Example: create three windows to sell tickets, and the total number of tickets is 100
 * There is now a thread security issue
 * @Author Jack
 * @Date 2021/11/21 23:33
 * @Version 1.0
 */
public class WindowTest {
    public static void main(String[] args) {
        Window w1 = new Window();
        Window w2 = new Window();
        Window w3 = new Window();

        w1.setName("Window one");
        w2.setName("Window II");
        w3.setName("Window three");
        w1.start();
        w2.start();
        w3.start();
    }
}

class Window extends Thread {
    private static int ticket = 100;
//    private static Object obj =new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (Window.class){
                if (ticket > 0) {
                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName() + ":Ticket number" + ticket);
                    ticket--;
                }else {
                    break;
                }
            }

        }
    }
}

The output results are as follows:
    .........
    .........

Window three:Selling tickets, ticket number 20
 Window three:Ticket No. 19
 Window II:Ticket No. 18
 Window II:Ticket No. 17
 Window three:Ticket No. 16
 Window three:Ticket No. 15
 Window three:Ticket No. 14
 Window three:Ticket No. 13
 Window three:Ticket No. 12
 Window three:Ticket No. 11
 Window three:Ticket No. 10
 Window three:Ticket No. 9
 Window one:Ticket No. 8
 Window three:Ticket No. 7
 Window three:Ticket No. 6
 Window three:Ticket No. 5
 Window three:Ticket No. 4
 Window three:Ticket No. 3
 Window II:Ticket No. 2
 Window three:Ticket number 1   

2. Lock in synchronization mechanism

In Thinking in Java, it is said that for concurrent work, you need some way to prevent two tasks from accessing the same resources (in fact, shared resource competition) . the way to prevent this conflict is to lock a resource when it is used by a task. The first task accessing a resource must lock the resource so that other tasks cannot access it before it is unlocked. When it is unlocked, another task can lock and use it.

What is a synchronized lock?

Any object can be used as a synchronous lock. All objects automatically contain a single lock (monitor).
Lock of synchronous method: static method (class name). class), non static method (this)
Synchronous code block: you can specify it yourself, and it is often specified as this or class name

be careful

It is very important to ensure that multiple threads using the same resource share a lock, otherwise the security of shared resources cannot be guaranteed

All static methods in a thread class share the same lock (class name. class), all non static methods share the same lock (this), and synchronize code blocks (be careful when specifying)

Scope of synchronization

1. How to find the problem, that is, whether there is thread safety in the code? (very important)
(1) Identify which code is multithreaded
(2) Specify whether multiple threads share data
(3) Specify whether there are multiple statements operating on shared data in multithreaded running code

2. How to solve it?
(very important)
For statements with data shared by multiple operations, only one thread can complete the execution. During the execution, other threads cannot participate in the execution.
That is, all these statements that operate on shared data should be placed in the synchronization range

3. Remember

The scope is too small: not all code with security problems is locked

Too wide range: it does not play the function of multithreading.

Operation of releasing lock

The execution of the synchronization method and synchronization code block of the current thread ends.
The current thread encountered break and return in the synchronization code block and synchronization method, and terminated the code block
The method continues.
The current thread has an unhandled Error or Exception in the synchronization code block and synchronization method. Please lead
Cause abnormal end.
The current thread executes the wait() method of the thread object in the synchronization code block and synchronization method
The process pauses and releases the lock. (the wait method will be mentioned later)

Operation that does not release the lock

When a thread executes a synchronization code block or synchronization method, the program calls Thread. sleep() and Thread.yield() methods to suspend the execution of the current thread

When a thread executes a synchronization code block, other threads call the thread's suspend() method to suspend the thread, and the thread will not release the lock (synchronization monitor).
Try to avoid using suspend() and resume() to control threads

Thread deadlock

Different threads occupy the synchronization resources needed by the other party and do not give up. They are waiting for the other party to give up the synchronization resources they need, forming a thread deadlock

After a deadlock occurs, there will be no exception or prompt, but all threads are blocked and cannot continue

as follows

package com.caq.www;

import static java.lang.Thread.sleep;

/**
 * @ClassName ThreadTest
 * @Description Demonstrate thread deadlock
 * 1.Understanding of Deadlock:
 * Different threads occupy the synchronization resources required by each other and do not give up,
 * They are waiting for the other party to give up the public resources they need, which forms a thread deadlock
 * 2.explain:
 * 1)After a deadlock occurs, there will be no exception or prompt, but all threads are blocked and cannot continue
 * 2)When we use synchronization, we should avoid deadlock
 * @Author Jack
 * @Date 2021/11/23 11:13
 * @Version 1.0
 */
public class ThreadTest {
    public static void main(String[] args) {
        StringBuffer s1 = new StringBuffer();
        StringBuffer s2 = new StringBuffer();

        //Start a Thread by inheriting the Thread class through the anonymous inner class
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized(s1){
                    s1.append("a");
                    s2.append("1");
                    //The thread holds the s1 lock and waits for the s2 lock
                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (s2){
                        s1.append("b");
                        s2.append("2");

                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }).start();

        //Start a new thread by implementing the Runnable interface
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized(s2){
                    s1.append("c");
                    s2.append("3");
                    //The thread holds the s2 lock and waits for the s1 lock
                    try {
                        sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (s1){
                        s1.append("d");
                        s2.append("4");

                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }).start();
    }
}

resolvent

Special algorithms and principles
Minimize the definition of synchronization resources
Try to avoid nested synchronization

3. Lock

Starting from JDK 5.0, Java provides a more powerful thread synchronization mechanism. First, synchronization is achieved by explicitly defining the synchronization Lock object. The synchronization Lock uses the Lock object as the synchronization object.

The java.util.concurrent.locks.Lock interface is a tool that controls multiple threads to access shared resources. Locks provide exclusive access to shared resources. Only one thread can Lock the Lock object at a time. Threads should obtain the Lock object before accessing shared resources.

ReentrantLock class implements Lock. It has the same concurrency and memory semantics as synchronized. ReentrantLock is commonly used in thread safety control, which can explicitly add and release locks.

Improved example

package com.caq.www;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @ClassName LockTest
 * @Description Three ways to solve thread safety problems: Lock lock -- new in JDK5.0
 *
 * 1.Interview question: similarities and differences between synchronized and Lock
 * Same: both can solve thread safety problems
 * Difference: the synchronized mechanism automatically releases the synchronization monitor after executing the corresponding synchronization code
 * lock You need to manually start synchronization (lock ()), and you also need to manually execute (unlock ()) to end synchronization
 *
 *
 * 2.Interview question: how to create multithreading?
 * 1.Override the run method by inheriting the Thread class. Generate the object of the subclass and call the start method
 * 2.By implementing the Runnable interface and passing the implementation class as a parameter to the constructor of the Thread class, create a Thread object and call start() to start the Thread
 *
 * 3.Interview question: how to solve thread safety problems? How many ways?
 * 1.Synchronize code blocks and methods through synchronized {synchronization method}
 * 2.By means of Lock lock, manually open the synchronization Lock to synchronize threads, and manually release the synchronization Lock to end
 *
 * @Author Jack
 * @Date 2021/11/23 15:57
 * @Version 1.0
 */

class Window implements Runnable{
    private int ticket = 100;
    //Instantiate ReentrantLock
    private ReentrantLock lock = new ReentrantLock(true);//If it is true, it is fair first in first out, and the default is false preemption

    @Override
    public void run() {
        while (true){
            try {

                //2. Call the lock method lock
                lock.lock();

                if (ticket > 0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":Ticket No.:"+ticket);
                    ticket--;
                }else {
                    break;
                }
            }finally {

                //3. Call unlocking method
                lock.unlock();
            }

        }

    }
}
public class LockTest {
    public static void main(String[] args) {
        Window w = new Window();

        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);

        t1.setName("Window one");
        t2.setName("Window II");
        t3.setName("Window three");

        t1.start();
        t2.start();
        t3.start();
    }
}

Note: if there is an exception in the synchronization code, write unlock() to the finally statement block

synchronized vs Lock

  1. Lock is an explicit lock (manually open and close the lock, don't forget to close the lock), and synchronized is an implicit lock, which is automatically released out of the scope
  2. Lock only has code block lock, and synchronized has code block lock and method lock
  3. Using Lock lock, the JVM will spend less time scheduling threads and perform better. And it has better extensibility (providing more subclasses)
  4. Priority:
    Lock - > synchronization code block (it has entered the method body and allocated corresponding resources) - > synchronization method (outside the method body)

4, Thread communication

It can be understood as alternation

wait() and notify() and notifyAll()

wait(): suspend the current thread, abandon the CPU, synchronize resources and wait, so that other threads can access and modify shared resources. The current thread queues up for other threads to call notify() or ntifyll() method to wake up. After waking up, it can continue to execute after regaining ownership of the monitor.

notify(): wakes up the thread with the highest priority waiting for synchronization resources and ends the wait

notifyAll(): wakes up all threads queued for resources and ends waiting

These three methods can only be used in the synchronized method or synchronized code block, otherwise java.langlegalmonitorstateexception will be reported.

Because these three methods must be called by a lock Object, and any Object can be used as a synchronized lock, these three methods can only be declared in the Object class.

example

package com.caq.java2;

/**
 * @ClassName CommunicatrionTEst
 * @Description Examples of thread communication; Use two threads to print 1-100. Thread 1, thread 2, alternate printing
 *
 * Three methods involved:
 * wait(): Once this method is executed, the current thread enters a blocking state and releases the synchronization monitor
 * notify(): Once this method is executed, a wait thread will wake up. If multiple threads are limited by wait, the thread with high priority will be released
 * nitifyAll(): Once this method is executed, all wait threads will wake up
 *
 * explain:
 * 1.wait, notify(),nitifyAll()The three methods must be used in synchronous code blocks or synchronous methods
 * 2.wait, notify(),nitifyAll()The three method callers must be synchronization monitors in synchronization blocks or synchronization methods
 * 3.wait, notify(),nitifyAll()All three methods are methods in the java.lang.Object class
 *      Otherwise, an IllegalMonitorStateException will occur
 *
 * Interview question: similarities and differences between sleep () and wait () methods
 * The same thing: once the method is executed, the thread will be blocked
 * Differences: 1) the positions of the two method declarations are inconsistent. One is Thread and the other is Object
 *        2)The call requirements are inconsistent. The sleep () method can be called in any need scenario, and the wait () must be used in the synchronization code block or synchronization method
 *        3)About whether to release the synchronization monitor: if both methods are used in the synchronization code block or synchronization method, sleep () will not release the lock, and wait () will release the lock
 *
 * @Author Jack
 * @Date 2021/11/23 22:52
 * @Version 1.0
 */
class Number implements Runnable{
    private int number = 1;
    @Override
    public void run() {
        while (true){
            synchronized (this) {
                notify();//When the thread 1 wait, release the lock. Thread 2 comes in and calls notify to wake up thread 1
                if (number < 100){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":"+number);
                    number++;

                    try {
                        //Make the thread calling the following wait () method enter the blocking state
                        //Entering the wait state will release the lock
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    break;
                }
            }
        }
    }
}

public class CommunicationTest {
    public static void main(String[] args) {
        Number number = new Number();

        Thread t1 = new Thread(number);
        Thread t2 = new Thread(number);

        t1.setName("Thread 1");
        t2.setName("Thread 2");

        t1.start();
        t2.start();

    }
}

Producer / consumer issues

package com.caq.java2;

/**
 * @ClassName ProductTest
 * @Description Application of thread communication: classic example: producer consumer problem
 * The producer gives the product to the clerk, and the customer takes the product from the clerk,
 * The clerk can only hold a fixed number of products (e.g. 20) at a time. If the producer tries to produce more products, the clerk will
 * The manufacturer will be asked to stop. If there is a space in the store for products, the manufacturer will be notified to continue production: if there is no product in the store
 * The clerk will tell the consumer to wait a minute and inform the consumer to take the product if there is a product in the store.
 * <p>
 * analysis:
 * 1.Is it a multithreading problem? Yes, producer thread, consumer thread
 * 2.Is there shared data? Yes, clerk (or product)
 * 3.How to solve the thread security problem? Synchronization mechanism, there are three methods
 * 4.Is thread communication involved? yes
 * @Author Jack
 * @Date 2021/11/23 23:21
 * @Version 1.0
 */
class Clerk {

    private int productCount = 0;

    //yield a product
    public synchronized void produceProduct() {
        if (productCount < 20){
            productCount++;
            System.out.println(Thread.currentThread().getName()+":Start production"+productCount+"Products");
            notify();
        }else {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //wait for

        }
    }

    //Consumer products
    public synchronized void consumeProduct() {
        if (productCount > 0){
            System.out.println(Thread.currentThread().getName()+":Start consumption"+productCount+"Products");
            productCount--;
            notify();
        }else {
            //wait for
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Producer extends Thread {//producer

    private Clerk clerk;

    public Producer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(getName() + ": Start production...");
        while (true) {
            try {
                sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.produceProduct();
        }
    }
}

class Consumer extends Thread {
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        while (true) {
            try {
                sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.consumeProduct();
        }
    }
}

public class ProductTest {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Producer p1 = new Producer(clerk);

        Consumer c1 = new Consumer(clerk);
        Consumer c2 = new Consumer(clerk);

        p1.setName("producer");
        p1.start();

        c1.setName("Consumer 1");
        c2.setName("Consumer 2");

        c1.start();
        c2.start();

    }
}

5, JDK5.0 new thread creation method

1. Implement Callable interface

Callable is more powerful than Runnable

Compared with the run() method, you can have a return value
Method can throw an exception
Return values that support generics
You need to use the Future Task class, for example, to get the returned results

Future interface

You can cancel the execution results of specific Runnable and Callable tasks, query whether they are completed, obtain results, etc.
FutrueTask is the only implementation class of Futrue interface
FutureTask also implements Runnable and Future interfaces. It can be executed by the thread as Runnable or get the return value of Callable as Future

Examples are as follows

package com.caq.java2;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @ClassName ThreadNew
 * @Description The third way to create a thread
 * Implement Callable interface -- jdk5.0
 *
 * How to understand that the way to implement the Callable interface to create multithreads is more powerful than the way to implement the Runnable interface to create multithreads?
 * 1.call()Can have return value
 * 2.call()Exceptions can be thrown and caught by external operations. Get exception information
 * 3.Callable It supports introspection
 *
 *
 * @Author Jack
 * @Date 2021/11/24 8:41
 * @Version 1.0
 */


//1. Create an implementation class that implements Callable
class NumThread implements Callable{
    //2. Implement the call method and declare the operation to be executed by this thread in call()
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 0; i <=100; i++) {
            if (i %2 ==0){
//                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}

public class ThreadNew {
    public static void main(String[] args) {
        //3. Create an object of the Callable interface implementation class
        NumThread numThread = new NumThread();

        //4. Pass the object of the Callable interface implementation class as a parameter to the FutureTask constructor to create the FutureTask object
        FutureTask futureTask = new FutureTask(numThread);

        //5. Pass the FutureTask object as a parameter to the constructor of the Thread class, create the Thread object, and call start()
        new Thread(futureTask).start();

        try {
            //6. Get the return value of call method in Callable
            //The return value of get () is the return value of call () overridden by the FutureTask constructor parameter Callable
            Object sum = futureTask.get();
            System.out.println(sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

2. Use thread pool

background

Frequently create and destroy resources that are heavily used, such as threads in concurrency, which has a great impact on performance

thinking

Create multiple threads in advance, put them into the thread pool, obtain them directly when using them, and put them back into the pool after use. It can avoid frequent creation, destruction and reuse. Similar to public transport in life

advantage

Improved response time (reduced time to create new threads)

Reduce resource consumption (reuse threads in the thread pool and do not need to be created every time)

Easy thread management

corePoolSize: the size of the core pool

maximumPoolSize: maximum number of threads

keepAliveTime: when the thread has no task, how long will it last at most and then terminate

...

Thread pool related API

JDK 5.0 provides thread pool related APIs: executorservice and Executors

ExecutorService: the real thread pool interface. Common subclass ThreadPoolExecutor

void execute(Runnable command): executes a task / command without a return value. It is generally used to execute Runnable
Future submit(Callable task): execute a task with a return value, and generally execute a Callable task
void shutdown(): closes the connection pool

Executors: tool class and factory class of thread pool, which are used to create and return different types of thread pools

Executors.newCachedThreadPool(): create a thread pool that can create new threads as needed
Executors.newFixedThreadPool(n); Create a reusable thread pool with a fixed number of threads
Executors.newSingleThreadExecutor(): create a thread pool with only one thread
Executors.newScheduledThreadPool(n): creates a thread pool that can schedule commands to run after a given delay or execute periodically

example

package com.caq.java2;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @ClassName ThreadPool
 * @Description Four ways to create threads:
 * Use thread pool
 * Benefits:
 * 1.Improved response time (reduced time to create new threads)
 * 2.Reduce resource consumption (reuse threads in the thread pool and do not need to be created every time)
 * 3.Easy thread management
 *      corePoolSize:Size of core pool
 *      maximumPoolsize:Maximum number of threads
 *      keepAliveTime:When a thread has no task, how long will it last at most and then terminate
 *
 * How many ways to create multithreading?
 * Four!
 *
 * @Author Jack
 * @Date 2021/11/24 9:13
 * @Version 1.0
 */

class NumberThread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 101; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
}

class NumberThread1 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 101; i++) {
            if (i % 2 != 0) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
}

public class ThreadPool {
    public static void main(String[] args) {
        //Executors.newFixedThreadPool(n); Create a reusable thread pool with a fixed number of threads
        //1. Provide a thread pool with a specified number of threads
        ExecutorService service = Executors.newFixedThreadPool(10);
        ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
        service1.setCorePoolSize(15);
//        service1.setKeepAliveTime();


        //Set the properties of the thread pool
        System.out.println(service.getClass());//ThreadPoolExecutor

        /**The purpose of providing parameters is to tell the thread what to do
        NumberThread numberThread = new NumberThread();
        service.execute(numberThread);
        Implementation of anonymous classes
         */
        //2. To execute the operation of the specified thread, you need to provide an object that implements the Runnable interface or Callable interface implementation class
        service.execute(new NumberThread());//For Runnable
        service.execute(new NumberThread1());
//        service.submit(Callable callable) is suitable for Callable

        //3. Close thread pool
        service.shutdown();
    }
}

Topics: Java