Java concurrency mechanism (understanding of Thinking in java)

1. Basic:

  1. When does thread safety issue occur?

    In multi-threaded programming, it may happen that multiple threads access a resource ( shared resource ) at the same time. Since the process of each thread is uncontrollable, the actual running result of the program is contrary to the wish.

  2. How to solve the thread safety problem?

    In general, all concurrency patterns adopt the "serialized access to critical resources" scheme: that is, only one thread is allowed to access critical resources at a time.

    The above method is also called: synchronous mutual exclusion access : add a place before the code that accesses the critical resource, and release the lock after the access. There are two ways to achieve mutual exclusion synchronization in java: synchronized and Lock ;

2, synchronized implementation 

  1. Three methods of synchronized locking and their corresponding principles:

    (1): synchronized modifies ordinary methods, and the lock scope is the instance scope : all objects automatically contain a single lock ( monitor ), when the synchronized method in the object is called, the object will be locked, and other objects in the object will be locked. Locked methods cannot be accessed by other threads. Such as:  Person(){ synchronized eat(){} synchronized run()}; When thread1 calls the eat of the object, thread2 cannot call the run method; 

      The underlying principle: For example, the ACC_SYNCHRONIZED identifier in the constant pool is used as the access identifier. When the method is called, first check whether the access flag is set. If so, the thread obtains the monitor first, and releases the monitor after the method is executed.

public synchronized void method(){
   System.out.println("Hello Word") ;    
}

     (2): synchronized modifies the static method, and the lock scope is the class scope : all Person class objects will be locked.

The eat1 method of thread 1 and thread 2 can only be called by one. The eat2 method is instance synchronized, thread 1 locks object 1, thread 2 locks object 2, and eat2 can be called synchronously by thread 1 and thread 2.

public class Person implements Runnable{
     static int apple=0;
       //Lock the current Class class object, that is, the Person class.
     public static synchronized void eat1(){
             i++;//Non-atomic operation;
     } 
    //Lock the current instance, that is, only lock one instance object of Person;
public synchronized void eat2(){
        i++;
   }
}

    (3): synchronized modifies the synchronization code block, and the scope is the instance object : sometimes it is unnecessary to lock the entire method, and it will also reduce the execution efficiency. All it needs is to lock certain steps in the method.

public class Person{
    private int apple=0;
    public void eat(){
        synchronized(this){
            apple++;
        }
    }
}  

 

 

 

 

 

 

 

 

 

  Note: A thread can acquire the lock of the object multiple times: if the object o1 calls the eat method, and eat calls the run method of the object, the jvm will automatically increase the number of locks, and each time it leaves a synchronized method, the count is decremented by one , up to 0.

       Note: For the optimization of synchronized, see the finishing later (to be added...).

3. Implementation of Local (Local interface under the java.util.concurrent.locks package)

  1. Why use Local with synchronized?

    (1) Defects of synchronized: There are only two execution results of synchronized [1] The lock is released after execution. [2] Exception, jvm releases the lock. But when a thread holding a lock is blocked (such as IO), then other threads can only wait. For another example, when multiple threads read files at the same time, there will be no conflict, but in order to avoid read and write conflicts, read operations are also synchronized, which is very inefficient.

    (2) The use of Local can solve the above problems. Moreover, Local is a class (interface) in java, which implements multiple methods to acquire and process locks; synchronized is a built-in keyword in the java language, and has no other function.

   2. How to use Local:

  (1): Declare within the method and lock and declare outside the method, lock within the method :

public class Test {
    private ArrayList<Integer> arrayList = new ArrayList<Integer>();
    public static void main(String[] args)  {
        final Test test = new Test();
         
        new Thread(){
            public void run() {
                test.insert(Thread.currentThread());
            };
        }.start();
         
        new Thread(){
            public void run() {
                test.insert(Thread.currentThread());
            };
        }.start();
    }  
     
    public void insert(Thread thread) {
        Lock lock = new ReentrantLock();   // Note that Lock is in the method, it is a local variable 
        lock.lock();
         try {
            System.out.println(thread.getName()+"得到了锁");
            for(int i=0;i<5;i++) {
                arrayList.add(i);
            }
        } catch (Exception e) {
            // TODO: handle exception
        }finally {
            System.out.println(thread.getName() + "released the lock" );
            lock.unlock();
        }
    }
}
Thread-0 got the lock
Thread-1 got the lock
Thread-0 released the lock
Thread-1 releases the lock 
//Thread 0 acquires the lock without affecting the acquisition of thread 1
 

 

public class Test {
    private ArrayList<Integer> arrayList = new ArrayList<Integer>();
    private Lock lock = new ReentrantLock();    //注意这个地方
    public static void main(String[] args)  {
        final Test test = new Test();
         
        new Thread(){
            public void run() {
                test.insert(Thread.currentThread());
            };
        }.start();
         
        new Thread(){
            public void run() {
                test.insert(Thread.currentThread());
            };
        }.start();
    }  
     
    public void insert(Thread thread) {
        if(lock.tryLock()) {
            try {
                System.out.println(thread.getName()+"得到了锁");
                for(int i=0;i<5;i++) {
                    arrayList.add(i);
                }
            } catch (Exception e) {
                // TODO: handle exception
            }finally {
                System.out.println(thread.getName() + "released the lock" );
                lock.unlock();
            }
        } else {
            System.out.println(thread.getName() + "Failed to acquire lock" );
        }
    }
}
// get sequentially
 

 

    

 

 

  

 

 

    

  

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324516150&siteId=291194637