Java multithreaded information sharing (volatile, synchronized, Lock)

Information Sharing

• Coarse-grained: lack of communication between sub-threads and sub-threads, and between the main thread
• Fine-grained: there is information exchange and communication between threads-information
sharing is achieved through shared variables
-JDK native library does not currently support sending messages (similar to MPI parallel The library sends the message directly)

• Share messages in multiple threads through shared variables
-static variables
-member variables of the same Runnable class
Insert picture description here

Insert picture description here
• Multi-threaded information sharing problem
-work cache copy
-lack of lock restrictions on key steps
• i++, not an atomic operation
-read main memory i (original) to work cache (copy)
-each CPU executes (copy) i+ 1 Operation
-CPU writes the result into the cache (copy)
-Data is flushed from the working cache (copy) to the main memory (original)
Insert picture description here

The solution to the problem of variable copy (volatile)

-Use the volatile keyword to modify variables (variables modified with volatile can be notified in each thread in time)
-Ensure the visibility of shared variable operations by different threads

public class ThreadDemo2
{
    
    
	public static void main(String args[]) throws Exception 
	{
    
    
		TestThread2 t = new TestThread2();
		t.start();
		Thread.sleep(2000);
		t.flag = false;
		System.out.println("main thread is exiting");
	}
}

class TestThread2 extends Thread
{
    
    
	//boolean flag = true;   //子线程不会停止
	volatile boolean flag = true;  //用volatile修饰的变量可以及时在各线程里面通知
	public void run() 
	{
    
    
		int i=0;
		while(flag)
		{
    
    
			i++;			
		}
		System.out.println("test thread3 is exiting");
	}	
} 

Key steps to lock restrictions(synchronized)

Critical resources and mutex locks
Data shared between multiple threads is called critical resource (Critical Resource).
Each object has a "mutual exclusion lock" mark to ensure that only one thread can access the object at any time.
In Java, synchronized is used to mark an object that can only be accessed by one thread at any time.
There are two ways to use the synchronized keyword

  1. Synchronization code block
synchronized (对象){
    
    
// 需要被同步的代码;
}
  1. Synchronized can also be placed in the method declaration, indicating that the entire method isSynchronization method. E.g:
public synchronized void show (String name){
    
    .
}

Runnable interface to solve thread safety

Method 1: Synchronize code blocks
Description:
1. The code for operating shared data is the code that needs to be synchronized. -->Cannot contain too much code, nor can it contain less code.
2. Shared data: variables operated by multiple threads.
3. Synchronization monitor, commonly known as: lock. Any object of a class can act as a lock.
Requirements: Multiple threads must share the same lock.

supplement:In the way of implementing the Runnable interface to create multiple threads, we can consider using this as a synchronization monitor.
(Use this class of objects as monitors, of course, you can also use any other objects)

class Window1 implements Runnable{
    
    

    private int ticket = 100;
//    Object obj = new Object();
//    Dog dog = new Dog();
    @Override
    public void run() {
    
    
//        Object obj = new Object();
        while(true){
    
    
            synchronized (this){
    
    //此时的this:唯一的Window1的对象
                //方式二:synchronized (dog) {
    
    
                if (ticket > 0) {
    
    

                    try {
    
    
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);


                    ticket--;
                } else {
    
    
                    break;
                }
            }
        }
    }
}

Window1 w = new Window1();

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

Method 2: Synchronization method.
If the code for operating shared data is completely declared in a method, we might as well declare this method synchronously.
Summary of synchronization methods:

  1. The synchronization method still involves the synchronization monitor, but we don't need an explicit statement.

  2. Non-static synchronization method, synchronization monitor is: this
    static synchronization method, synchronization monitor is: the current class itself

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

        show();
    }
}

private synchronized void show(){
    
    //同步监视器:this
    //synchronized (this)**可以使用{
    
    

        if (ticket > 0) {
    
    

            try {
    
    
                Thread.sleep(100);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);

            ticket--;
        }
    //}
}

Solve thread safety by inheriting the Thread class

Note: Add static()
Method 1: Code block
Description: In the way of inheriting the Thread class to create multiple threads,Use with cautionThis acts as a synchronization monitor, consider using the current class as a synchronization monitor. (This represents the three objects t1, t2, t3)

class Window2 extends Thread {
    
    

    private static int ticket = 100;

    private static Object obj = new Object();

    @Override
    public void run() {
    
    

        while (true) {
    
    
            //正确的
//            synchronized (obj){
    
    
            synchronized (Window2.class) {
    
    //Class clazz = Window2.class,Window2.class只会加载一次
                //错误的方式:this代表着t1,t2,t3三个对象
//              synchronized (this){
    
    

                if (ticket > 0) {
    
    

                    try {
    
    
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }

                    System.out.println(getName() + ":卖票,票号为:" + ticket);
                    ticket--;
                } else {
    
    
                    break;
                }
            }

        }

    }
}
   Window2 t1 = new Window2();
    Window2 t2 = new Window2();
    Window2 t3 = new Window2();

Use synchronous methods to deal with thread safety issues in the way of inheriting the Thread class

@Override
public void run() {
    
    

    while (true) {
    
    

        show();
    }

}

private static synchronized void show(){
    
    //同步监视器:Window4.class
    //private synchronized void show(){ //同步监视器:t1,t2,t3。此种解决方式是错误的
    if (ticket > 0) {
    
    

        try {
    
    
            Thread.sleep(100);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);
        ticket--;
    }
}

Synchronization lock mechanism:

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

What is the synchronized lock?

  • Any object can be used as a synchronization lock . All objects automatically contain a single lock (monitor).

  • Synchronous method lock: static method (class name.class), non-static method (this)

  • Synchronous code block: specify by yourself, in many cases it is also specified as this or class name.class

note:

  • Must ensure that the same resource is usedMultiple threads share a lock, This is very important, 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), synchronization code block (specify caution)

Scope of synchronization

1. How to find the problem, that is, is the code thread safe? (Very important)
(1) Clarify which code is multi-threaded code
(2) Clarify whether multiple threads have shared data
(3) Clarify whether there are multiple statements operating shared data in the multi-threaded code

2. How to solve it? (Very important)
For statements that share data for multiple operations, only one thread can be executed, and other threads cannot participate in the execution during the execution. That is, all these statements that operate on shared data must be placed in the synchronization scope

3. Remember:

  • The range is too small: all code with security issues is not locked

  • The scope is too large: the function of multi-threading is not used.

Operation to release the lock

  • The execution of the synchronization method and synchronization code block of the current thread ends.
  • The current thread encounters a break and return in a synchronized code block and a synchronized method to terminate the code block, and the method continues to execute.
  • The current thread has an unhandled Error or Exception in the synchronization code block or synchronization method, resulting in an abnormal end.
  • The current thread executes the method of the thread object in the synchronization code block and synchronization wait()method, the current thread is suspended, and the lock is released.

Operations that do not release the lock

  • When a thread executes a synchronized code block or a synchronized method, the program call Thread.sleep()or Thread.yield()method suspends 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).
    Should try to avoid using suspend() and resume() to control threads

Lock

  • Starting from JDK 5.0, Java provides a more powerful thread synchronization mechanism-synchronization is achieved by explicitly defining synchronization lock objects. Synchronization locks use Lock objects to act as.

  • The java.util.concurrent.locks.Lock interface is a tool for controlling multiple threads to access shared resources. The lock provides exclusive access to shared resources. Only one thread can lock the Lock object at a time. The Lock object should be acquired before the thread starts to access the shared resource.

  • The ReentrantLock class implements Lock, which has the same concurrency and memory semantics as synchronized. In the realization of thread-safe control, ReentrantLock is more commonly used, which can explicitly lock and release locks.
    Insert picture description here

Comparison of synchronized and Lock

  1. Lock is an explicit lock ( manually open and close the lock , don’t forget to close the lock), synchronized is an implicit lock that is automatically released out of scope

  2. Lock only has code block lock, synchronized has code block lock and method lock

  3. Using Lock locks, JVM will spend less time to schedule threads, better performance. And has better scalability (provide more sub-categories)

Priority order:
Lock => Synchronization code block (has entered the method body and allocated corresponding resources) => Synchronization method (outside the method body)

Guess you like

Origin blog.csdn.net/weixin_46168350/article/details/113101592