Eleven, java multithreading basis of the depth of the lock

A reentrant lock

1. lock as a concurrent share data to ensure consistency of tools, JAVA platform in multiple implementations (such as synchronized (heavyweight) and ReentrantLock (lightweight), and so on). These locks have been written offer to provide convenience for our development. Reentrant lock, also known as recursive locks, referring to the same thread after the outer function to obtain a lock, the inner recursive functions still have to acquire the lock code, but is not affected.
2. In ReentrantLock JAVA environment and are synchronized reentrant lock.

3. Code

//重入锁  轻量级(Lock)与重量级锁(synchronized)---可重入性(递归锁)
public class Test001 implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        set();
    }
    //synchronized代码块执行完毕的时候释放锁
    private synchronized void set() {
        System.out.println("set方法");
        get();
    }
    private synchronized void get() {
        System.out.println("synchronized  可具备可重入性-get方法");
    }
    public static void main(String[] args) {
        Test001 test001 = new Test001();
        Thread thread = new Thread(test001);
        thread.start();
        System.out.println(Thread.currentThread().getName()+"主线程结束");
    }
}

4. Results

main主线程结束
set方法
synchronized  可具备可重入性-get方法

5. Code

//演示lock锁是否具备  可重入性(特征:锁可以传递(方法递归传递)),下面的方法为啥会调两次,因为最后一次调用他已经知道第一次已经上锁了(不会在重新获取锁)
public class Test002 implements Runnable {
    Lock lock = new ReentrantLock();

    @Override
    public void run() {
        set();
    }

    private void set() {
        try {
            //上锁
            lock.lock();
            System.out.println("set方法");
            get();
        } catch (Exception e) {
            //重入锁的目的就是避免死锁
        } finally {
            lock.unlock();//释放锁
        }
    }

    private void get() {
        try {
            lock.lock();
            System.out.println("lock  可具备可重入性-get方法");
        } catch (Exception e) {

        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        Test002 test002 = new Test002();
        Thread thread = new Thread(test002);
        thread.start();
    }
}

6. Results

set方法
lock  可具备可重入性-get方法

Second, read-write locks

1. Compared Java in the lock (Locks in Java) in Lock implementation, read-write locks more complicated. Suppose your program involves a number of read and write operations to shared resources, read and write operations are not so frequent. In the absence of a write operation , two threads to read a resource without any problems, it should allow multiple threads can read the shared resource at the same time. But if there is a thread want to write these shared resources, we should no longer have the resources to other threads to read or write (Translator's Note: In other words: Read - can coexist, read - write can not coexist, write - write We can not coexist). This requires a read / write lock to solve this problem. In Java5 java.util.concurrent package already contains a read-write lock. Nevertheless, we should understand the principles behind its implementation.

2. Code

//读写锁  jvm内置缓存
public class Test003 {
    private volatile Map<String,String> caChe = new HashMap<>();
    //读写锁
    private ReentrantReadWriteLock  rw1 = new ReentrantReadWriteLock();
    //写入锁
    private WriteLock writeLock = rw1.writeLock();
    //读出锁
    private ReadLock readLock = rw1.readLock();
    //写入元素
    public void put(String key,String value){
        try {
            writeLock.lock();
            System.out.println("正在做写的操作,key:" + key + ",value:" + value + "开始.");
            Thread.sleep(100);
            caChe.put(key,value);
            System.out.println("正在做写的操作,key:" + key + ",value:" + value + "结束.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            writeLock.unlock();
        }
    }
    //读取元素
    public String get(String key){
        try {
            readLock.lock();
            System.out.println("正在做读的操作,key:" + key + ",开始.");
            Thread.sleep(100);
            String value = caChe.get(key);
            System.out.println("正在做读的操作,key:" + key + ",结束.");
            return value;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return null;
        }finally {
            readLock.unlock();
        }
    }

    public static void main(String[] args) {
        Test003 test003 = new Test003();
        //写线程
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0;i<10;i++){
                    test003.put("i",i+"");
                }
            }
        });
        //读线程
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0;i<10;i++){
                    test003.get(i+"");
                }
            }
        });
        t1.start();
        t2.start();
    }
}

3. Results

正在做写的操作,key:i,value:0开始.
正在做写的操作,key:i,value:0结束.
正在做写的操作,key:i,value:1开始.
正在做写的操作,key:i,value:1结束.
正在做读的操作,key:0,开始.
正在做读的操作,key:0,结束.
正在做写的操作,key:i,value:2开始.
正在做写的操作,key:i,value:2结束.
正在做写的操作,key:i,value:3开始.
正在做写的操作,key:i,value:3结束.
正在做写的操作,key:i,value:4开始.
正在做写的操作,key:i,value:4结束.
正在做读的操作,key:1,开始.
正在做读的操作,key:1,结束.
正在做写的操作,key:i,value:5开始.
正在做写的操作,key:i,value:5结束.
正在做写的操作,key:i,value:6开始.
正在做写的操作,key:i,value:6结束.
正在做写的操作,key:i,value:7开始.
正在做写的操作,key:i,value:7结束.
正在做读的操作,key:2,开始.
正在做读的操作,key:2,结束.
正在做写的操作,key:i,value:8开始.
正在做写的操作,key:i,value:8结束.
正在做写的操作,key:i,value:9开始.
正在做写的操作,key:i,value:9结束.
正在做读的操作,key:3,开始.
正在做读的操作,key:3,结束.
正在做读的操作,key:4,开始.
正在做读的操作,key:4,结束.
正在做读的操作,key:5,开始.
正在做读的操作,key:5,结束.
正在做读的操作,key:6,开始.
正在做读的操作,key:6,结束.
正在做读的操作,key:7,开始.
正在做读的操作,key:7,结束.
正在做读的操作,key:8,开始.
正在做读的操作,key:8,结束.
正在做读的操作,key:9,开始.
正在做读的操作,key:9,结束.

Third, pessimistic locking and optimistic locking

1. pessimistic locking

Always assume the worst case, every other thread modifies think when fetching data, it will lock (read lock, write lock, line lock, etc.), when other threads that want to access the data, you need to hang blocked . Can rely on database implementation, such as row locks, read and write locks, are locked before the operation, in Java, synchronized thinking is pessimistic locking.

2. Optimistic locking

2.1. Always think no concurrency issues, each time to get the data and believe that there will be no other threads to modify the data, it will not be locked, but when the update will determine another thread before that there is no modify the data, usually a version number or CAS operating mechanism to achieve.

 version: Normal plus a data version number is the version field in the data table represents the number of data is modified, and when data is modified, plus a version value. When a thread A to update the data values ​​will be read version value while reading data, when submitting the update, if just to read the version when the update is version equal value in the current database, or retry update until the update is successful.

Core SQL statements

update table set x=x+1, version=version+1 where id=#{id} and version=#{version};    

CAS operation: i.e., compare and swap, or compare and set, involving three operands, where the data memory value, expected value, the new value. When needs to be updated, it is determined to take a value before the current value of the memory are equal, if equal, updated with the new value, if the retry fails, a general spin operation, i.e. continuously retries.

2.2. Examples

To take a simple example: suppose the account information in the database table has a version field, a current value of 1; field and the current account balance (Balance) is $ 100.

  1. At this time, the operator A to read out (version = 1), and deducting the $ 50 ($ 100- $ 50) from the account balance.
  2. During operation of the operator A, the operator B also reads the user information (version = 1), and deducted from the account balance is $ 20 ($ 100- $ 20).
  3. The operator A complete revision of the data version number plus one (version = 2), together with the account deductions balance (balance = $ 50), committed to the database update, this time due to submit data version is greater than the database records the current version of the data is updated database record is updated to version 2.
  4. The operator B to complete the operation, but also the version number plus one (version = 2) try to submit data (balance = $ 80) to the database, but this time than the discovery of the database record version, data version number of the operator B, filed 2 , the database also records the current version 2, does not meet the "submit version must be greater than the current version of the record in order to perform the update," the optimistic locking strategy, therefore, the operator B submission was rejected.

Thus, to avoid the operator B with the cover of the operation result of operator A may be based on the old version = 1 modified data results.

Fourth, the end of the

Always keep the faith!!!

Published 122 original articles · won praise 64 · views 50000 +

Guess you like

Origin blog.csdn.net/chenmingxu438521/article/details/103872814