Lock mechanism: synchronized, Lock, Condition

Original Address: https://blog.csdn.net/vking_wang/article/details/9952063 


1、synchronized


The code block is the synchronized statement, there are two important consequences, generally refers to the tag having atomic (Atomicity) and visibility (visibility).

1.1 atomicity
atomicity mean time, only one thread can execute a piece of code, the code via a monitor object protection. Thereby preventing multiple threads in conflict when updating shared state.

1.2 Visibility
Visibility is more subtle, it is to deal with cache and memory compilers optimized for a variety of abnormal behavior. It must ensure that the changes before releasing locks on shared data is then made to obtain the lock another thread is visible.

Role: Without this synchronization mechanism to ensure the visibility provided by the thread to see the shared variable values ​​may be inconsistent or before the amendment, which will lead to many serious problems.

How it works: When an object to acquire the lock, it first makes its own cache is invalid, so as to ensure variable load directly from the main memory. Similarly, before the object the lock is released, it will refresh its cache, forced to make any changes have been made to appear in the main memory. Thus, the same value will be guaranteed to see the changes in the two variables synchronized block thread synchronization with a lock.

In general, the thread does not have to let some other threads can immediately see the way (regardless of the threads in the register, in particular the processor cache, or rearranged by instruction or other compiler optimization), not variable cache constraint value, but if the developer uses a synchronous, then the runtime will ensure that a thread updates made to update the variables in the existing synchronized block performed when entering protected by the same monitor (lock) another when a synchronized block, will immediately see the updates made to the variables. Similar rules also exist on the volatile variables.

--volatile only guarantee visibility, does not guarantee the atomicity!

1.3 When you want to sync?
The basic rule is that the visibility of synchronization must be synchronized in the following cases: 

The variable may be read once written by another thread of 
a write once may be provided by another thread reads the variable
consistency of synchronization: When modifying multiple related values, other threads that you want to see this group of atoms changes - either to see all the changes, or nothing at all.

This applies to related data items (such as the location and velocity of particles) and the metadata items (e.g., data values ​​and a list of data items chain itself included in the list).

In some cases, you do not have to synchronize to pass data from one thread to another, because the JVM has performed for you sync implicitly. These include:

(Or static {} static field is initialized in the block) by a static initializer
during initialization data 
access final field --final object?
Before you create a thread when you create an object 
when a thread can see an object will be processed


1.4 synchronize restrictions
synchronized is good, but it's not perfect. It has some functional limitations:

It can not interrupt a thread is waiting to acquire a lock;
can not be locked by voting, I do not want to wait, it can not be locked;
synchronization also requires the release of the lock can only lock in and get the same stack frame where the stack frame carried out, in most cases, this is no problem (with the exception handling and interacts well), however, it does have some more suitable non-locking block structure of the situation.


2、ReentrantLock


Lock framework in java.util.concurrent.lock is an abstract lock, which allows locked implemented as Java classes, rather than as a language feature to achieve. This is the realization of a variety Lock left a space, various implementations may have different scheduling algorithms, performance characteristics or lock semantics.

ReentrantLock class implements Lock, it has synchronized with the same concurrency and memory semantics, but adds a similar vote lock, waiting time lock and lock some of the features may interrupt waiting. In addition, it provides under fierce contention for better performance. (In other words, when many threads want to access shared resources, JVM can spend less time scheduling threads and more time on the thread of execution.)

class Outputter1 {  
    private Lock lock = new ReentrantLock();// 锁对象  
 
    public void output(String name) {         
        lock.lock();      // 得到锁  
 
        try {  
            for(int i = 0; i < name.length(); i++) {  
                System.out.print(name.charAt(i));  
            }  
        } finally {  
            lock.unlock();// 释放锁  
        }  
    }  
}  

the difference:

Note that, with sychronized modified method or block of statements after the code executing the automatic lock release, but with Lock we need to manually release the lock, so to ensure that the final lock is released (abnormal case), should mutually exclusive zone placed inside try, release the lock on the inside finally! !

3, read-write lock ReadWriteLock


In the example shown are synchronized and the same functionality, where the advantages of Lock it in?
For example, a class provides its internal data of the shared data get () and set () method, if the synchronized, the code is as follows:

class syncData {      
    private int data;// 共享数据      
    public synchronized void set(int data) {  
        System.out.println(Thread.currentThread().getName() + "准备写入数据");  
        try {  
            Thread.sleep(20);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        this.data = data;  
        System.out.println(Thread.currentThread().getName() + "写入" + this.data);  
    }     
    public synchronized  void get() {  
        System.out.println(Thread.currentThread().getName() + "准备读取数据");  
        try {  
            Thread.sleep(20);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println(Thread.currentThread().getName() + "读取" + this.data);  
    }  
}  

Then write a test class to use multiple threads to read and write data are shared:

public static void main(String[] args) {  
//        final Data data = new Data();  
          final syncData data = new syncData();  
//        final RwLockData data = new RwLockData();  
        
        //写入
        for (int i = 0; i < 3; i++) {  
            Thread t = new Thread(new Runnable() {  
                @Override
        public void run() {  
                    for (int j = 0; j < 5; j++) {  
                        data.set(new Random().nextInt(30));  
                    }  
                }  
            });
            t.setName("Thread-W" + i);
            t.start();
        }  
        //读取
        for (int i = 0; i < 3; i++) {  
            Thread t = new Thread(new Runnable() {  
                @Override
        public void run() {  
                    for (int j = 0; j < 5; j++) {  
                        data.get();  
                    }  
                }  
            });  
            t.setName("Thread-R" + i);
            t.start();
        }  
    }  

Run Results:
Thread-W0 ready to write data
Thread-W0 writes 0
Thread-W0 ready to write data
Thread-W0 writes. 1
Thread-R1 ready to read data
Thread-R1 read. 1
Thread-R1 ready to read data
Thread -R1 read. 1
Thread-R1 ready to read data
Thread-R1 read. 1
Thread-R1 ready to read data
Thread-R1 read. 1
Thread-R1 ready to read data
Thread-R1 read. 1
the Thread-R2 ready to read data
Thread-R2 read. 1
Thread-R2 ready to read data
Thread-R2 read. 1
Thread-R2 ready to read data
Thread-R2 read. 1
Thread-R2 ready to read data
Thread-R2 read. 1
Thread-R2 preparation read data
Thread-R2 reads 1
the Thread-R0 ready to read data // R0 and R2 can be read at the same time, you should not be mutually exclusive!
Thread-R0 read. 1
Thread-R0 ready to read the data
read-R0. 1 the Thread
Thread-R0 ready to read data
Thread-R0 read. 1
Thread-R0 ready to read data
Thread-R0 read. 1
Thread-R0 ready to read data
Thread-R0 read. 1
Thread-W1 ready to write data
Thread-W1 is written 18 is
Thread-W1 ready to write the data
Thread-W1 is written 16
Thread-W1 ready to write data
Thread-W1 is written. 19
Thread-W1 ready to write data
Thread-W1 is written 21 is
Thread-W1 ready to write data
Thread-W1 is written. 4
the Thread-W2 of preparing to write data
Thread-W2 write 10
Thread-W2 to be written into the data
Thread-W2 written. 4
Thread-W2 to be written into the data
Thread-W2 written. 1
Thread-W2 to be written into the data
Thread-W2 writes 14
the Thread -W2 ready to write data
Thread-W2 write 2
Thread-W0 ready to write data
Thread-W0 writes. 4
Thread-W0 data to be written into
the write 20 is Thread-W0
Thread-W0 ready to write data
Thread-W0 writes 29

Now everything looks good! Each thread without disturbing each other! and many more. . Read thread and the write thread without disturbing each other is normal, but two threads need to read without disturbing each other? ?
Correct! Read the thread should not be mutually exclusive!

We can read and write lock ReadWriteLock achieve:

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

    class Data {      
        private int data;// 共享数据  
        private ReadWriteLock rwl = new ReentrantReadWriteLock();     
        public void set(int data) {  
            rwl.writeLock().lock();// 取到写锁  
            try {  
                System.out.println(Thread.currentThread().getName() + "准备写入数据");  
                try {  
                    Thread.sleep(20);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
                this.data = data;  
                System.out.println(Thread.currentThread().getName() + "写入" + this.data);  
            } finally {  
                rwl.writeLock().unlock();// 释放写锁  
            }  
        }     
 
        public void get() {  
            rwl.readLock().lock();// 取到读锁  
            try {  
                System.out.println(Thread.currentThread().getName() + "准备读取数据");  
                try {  
                    Thread.sleep(20);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
                System.out.println(Thread.currentThread().getName() + "读取" + this.data);  
            } finally {  
                rwl.readLock().unlock();// 释放读锁  
            }  
        }  
    }  


Test Results:

Thread-W1 ready to write data
Thread-W1 is written. 9
Thread-W1 ready to write data
Thread-W1 is written 24
Thread-W1 ready to write data
Thread-W1 is written 12 is
Thread-W0 ready to write data
Thread-W0 write the 22 is
Thread-W0 ready to write data
Thread-W0 writes 15
Thread-W0 ready to write data
Thread-W0 writes. 6
Thread-W0 ready to write data
Thread-W0 writes 13 is
Thread-W0 ready to write data
Thread- W0 writes 0
Thread-W2 to be written into the data
Thread-W2 write 23 is
Thread-W2 to be written into the data
Thread-W2 write 24
Thread-W2 to be written into the data
Thread-W2 write 24
Thread-W2 ready to write data
Thread-W2 written. 17
Thread-W2 to be written into the data
Thread-W2 writes 11
the Thread-R2 ready to read data
Thread-R1 ready to read data
Thread-R0 ready to read data
Thread-R0 read 11
Thread-R1 read. 11
Thread-R2 reading. 11
Thread-W1 ready to write data
Thread-W1 is written 18 is
Thread-W1 ready to write data
Thread-W1 is written. 1
the Thread-R0 ready to read data
Thread-R2 ready to be read data fetch
Thread-R1 ready to read data
Thread-R2 read. 1
Thread-R2 ready to read data
Thread-R1 read. 1
Thread-R0 read. 1
Thread-R1 ready to read data
Thread-R0 ready to read data
Thread- R0 is read. 1
the Thread read-R2. 1
the Thread-R2 ready to read data
Thread-R1 read. 1
Thread-R0 ready to read data
Thread-R1 ready to read data
Thread-R0 read. 1
the Thread read-R2. 1
the Thread -R1 1 reads
the Thread-R0 ready to read data
Thread-R1 ready to read data
Thread-R2 ready to read data
Thread-R1 1 reads
Thread-R2 1 reads
the Thread 1 read-R0


Compared with the mutex locked, read - write lock allows shared data a higher level of concurrent access. Although only one thread (writer thread) can modify the shared data, but in many cases, any number of threads can read shared data (reader threads) simultaneously

In theory, compared with the mutex lock, use a read - write lock allowed concurrency enhancements will bring even greater performance increase.

In practice, only on multiprocessor and only applies to shared data access mode, in order to fully implement concurrency enhancements. - For example, an initially populated with data and then less frequently modify the collection, because often their search (such as searching for some directory), so this collection is the use of reading - ideal candidates for write lock.

4, inter-thread communication Condition


Condition can replace traditional thread communication and replaced with await () wait (), alternatively notify () with Signal (), notifyAll replaced with signalAll () ().

- Why the method name does not directly call wait () / notify () / nofityAll ()? Because Object of these methods is final and can not be rewritten!

Traditional means of communication thread, Condition can be achieved.

Note, Condition is bound to Lock, to create a Lock of Condition must newCondition () method.

The power of Condition is that it can create different Condition is among multiple threads

Look at an example JDK documentation: Suppose there is a binding buffer which supports put and take methods. If you try to perform operations take on an empty buffer, before a certain item becomes available, the thread will block; if you try to perform a put operation on the buffer is full, then the space becomes available before the thread will It has been blocked. We like to put threads and take hold in a separate thread wait set, so that you can become the best use planning available, once notified only one thread in the buffer space or item. Condition can use two examples to do this.

- it is actually a function of java.util.concurrent.ArrayBlockingQueue


 

class BoundedBuffer {
   final Lock lock = new ReentrantLock();          //锁对象
   final Condition notFull  = lock.newCondition(); //写线程锁
   final Condition notEmpty = lock.newCondition(); //读线程锁
 
   final Object[] items = new Object[100];//缓存队列
   int putptr;  //写索引
   int takeptr; //读索引
   int count;   //队列中数据数目
 
   //写
   public void put(Object x) throws InterruptedException {
     lock.lock(); //锁定
     try {
       // 如果队列满,则阻塞<写线程>
       while (count == items.length) {
         notFull.await(); 
       }
       // 写入队列,并更新写索引
       items[putptr] = x; 
       if (++putptr == items.length) putptr = 0; 
       ++count;
 
       // 唤醒<读线程>
       notEmpty.signal(); 
     } finally { 
       lock.unlock();//解除锁定 
     } 
   }
 
   //读 
   public Object take() throws InterruptedException { 
     lock.lock(); //锁定 
     try {
       // 如果队列空,则阻塞<读线程>
       while (count == 0) {
          notEmpty.await();
       }
 
       //读取队列,并更新读索引
       Object x = items[takeptr]; 
       if (++takeptr == items.length) takeptr = 0;
       --count;
 
       // 唤醒<写线程>
       notFull.signal(); 
       return x; 
     } finally { 
       lock.unlock();//解除锁定 
     } 
   } 
}


advantage:

Suppose buffer queue is already full, then blocked certainly write thread, wake certainly read a thread, on the contrary, blocked thread must be read, write is certainly wake up the thread.

I assume there is only one Condition what effect? Buffer queue is already full, this is a wake-Lock does not know to read or write thread thread, and if awakened thread is read, everyone is happy, if the wake is to write a thread, the thread had just been awakened, has been blocked, then I went to the wake, thus wasting a lot of time.


--------------------- 
Author: AlphaWang 
Source: CSDN 
Original: https: //blog.csdn.net/vking_wang/article/details/9952063 
Disclaimer: This article as a blogger original article, reproduced, please attach Bowen link!

Guess you like

Origin blog.csdn.net/star1210644725/article/details/92982257