zoukankan      html  css  js  c++  java
  • Java Lock ReentrantLock ReentrantReadWriteLock

    Lock与Synchronized的区别:

        1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;

      2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

      3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

      4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

      5)Lock可以提高多个线程进行读操作的效率。

      在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。

    ReentrantLock:

    import java.util.*;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Main {
        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();
        }
    }
    
    class Test {
        private ArrayList<Integer> arrayList = new ArrayList<Integer>();
        private Lock lock = new ReentrantLock();    //注意这个地方
    
        public void insert(Thread thread) {
            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()+"释放了锁");
                lock.unlock();
            }
        }
    }
    Thread-0得到了锁
    Thread-0释放了锁
    Thread-1得到了锁
    Thread-1释放了锁
    View Code

    tryLock的使用:

    tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。

    tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。

    import java.util.*;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Main {
        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();
        }
    }
    class Test {
        private ArrayList<Integer> arrayList = new ArrayList<Integer>();
        private Lock lock = new ReentrantLock();    //注意这个地方
        
        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()+"释放了锁");
                    lock.unlock();
                }
            } else {
                System.out.println(thread.getName()+"获取锁失败");
            }
        }
    }
    Thread-0得到了锁
    Thread-0释放了锁
    Thread-1获取锁失败

    lockInterruptibly()响应中断方法:

    lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。

    由于lockInterruptibly()的声明中抛出了异常,所以lock.lockInterruptibly()必须放在try块中或者在调用lockInterruptibly()的方法外声明抛出InterruptedException。

    注意,当一个线程获取了锁之后,是不会被interrupt()方法中断的。因为本身在前面的文章中讲过单独调用interrupt()方法不能中断正在运行过程中的线程,只能中断阻塞过程中的线程。

    因此当通过lockInterruptibly()方法获取某个锁时,如果不能获取到,只有进行等待的情况下,是可以响应中断的。

    而用synchronized修饰的话,当一个线程处于等待某个锁的状态,是无法被中断的,只有一直等待下去。

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Main {
        public static void main(String[] args) {
            Test test = new Test();
            MyThread thread1 = new MyThread(test);
            MyThread thread2 = new MyThread(test);
            thread1.start();
            thread2.start();
    
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            thread2.interrupt();
        }
    }
    class Test {
        private Lock lock = new ReentrantLock();
    
        public void insert(Thread thread) throws InterruptedException{
            lock.lockInterruptibly();   //注意,如果需要正确中断等待锁的线程,必须将获取锁放在外面,然后将InterruptedException抛出
            try {
                System.out.println(thread.getName()+"得到了锁");
                long startTime = System.currentTimeMillis();
                for(    ;     ;) {
                    if(System.currentTimeMillis() - startTime >= Integer.MAX_VALUE)
                        break;
                    //插入数据
                }
            }
            finally {
                System.out.println(Thread.currentThread().getName()+"执行finally");
                lock.unlock();
                System.out.println(thread.getName()+"释放了锁");
            }
        }
    }
    
    class MyThread extends Thread {
        private Test test = null;
        public MyThread(Test test) {
            this.test = test;
        }
        @Override
        public void run() {
    
            try {
                test.insert(Thread.currentThread());
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName()+"被中断");
            }
        }
    }
    Thread-0得到了锁
    Thread-1被中断
    View Code

    读写锁:ReentrantReadWriteLock()

    使用syschronized读

    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class Main {
        public static void main(String[] args) {
            final Test test = new Test();
    
            new Thread(){
                public void run() {
                    test.get(Thread.currentThread());
                };
            }.start();
    
            new Thread(){
                public void run() {
                    test.get(Thread.currentThread());
                };
            }.start();
        }
    }
    
    class Test {
        private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    
        public synchronized void get(Thread thread) {
            long start = System.currentTimeMillis();
            while(System.currentTimeMillis() - start <= 1) {
                System.out.println(thread.getName()+"正在进行读操作");
            }
            System.out.println(thread.getName()+"读操作完毕");
        }
    }
    View Code
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0读操作完毕
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1读操作完毕
    View Code

    使用Lock的读锁

    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class Main {
        public static void main(String[] args) {
            final Test test = new Test();
    
            new Thread(){
                public void run() {
                    test.get(Thread.currentThread());
                };
            }.start();
    
            new Thread(){
                public void run() {
                    test.get(Thread.currentThread());
                };
            }.start();
        }
    }
    
    class Test {
        private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    
        public void get(Thread thread) {
            rwl.readLock().lock();
            try {
                long start = System.currentTimeMillis();
    
                while(System.currentTimeMillis() - start <= 1) {
                    System.out.println(thread.getName()+"正在进行读操作");
                }
                System.out.println(thread.getName()+"读操作完毕");
            } finally {
                rwl.readLock().unlock();
            }
        }
    }
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-1正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0正在进行读操作
    Thread-0读操作完毕
    Thread-1正在进行读操作
    Thread-1读操作完毕
    View Code

    读写锁表示两个锁,一个是读操作相关的锁,称为共享锁;另一个是写操作相关的锁,称为排他锁。我把这两个操作理解为三句话:

    1、读和读之间不互斥,因为读操作不会有线程安全问题

    2、写和写之间互斥,避免一个写操作影响另外一个写操作,引发线程安全问题

    3、读和写之间互斥,避免读操作的时候写操作修改了内容,引发线程安全问题

    总结起来就是,多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作

    注意的是,如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。

    如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,则申请的线程会一直等待释放写锁。

    加读锁的目的是防止写锁,加写锁的目的是为了防止读锁和写锁,读锁本身并不防止读锁。

    ReentrantReadWriteLock代码分析:http://blog.csdn.net/prestigeding/article/details/53286756

    http://www.cnblogs.com/dolphin0520/p/3923167.html

    http://blog.csdn.net/aitangyong/article/details/38315885

    http://www.cnblogs.com/benshan/p/3551987.html

    http://ifeve.com/java_lock_see/

    http://agapple.iteye.com/blog/970055

    https://www.cnblogs.com/szlbm/p/5588512.html

  • 相关阅读:
    UVA 11488 Hyper Prefix Sets (字典树)
    UVALive 3295 Counting Triangles
    POJ 2752 Seek the Name, Seek the Fame (KMP)
    UVA 11584 Partitioning by Palindromes (字符串区间dp)
    UVA 11100 The Trip, 2007 (贪心)
    JXNU暑期选拔赛
    计蒜客---N的-2进制表示
    计蒜客---线段的总长
    计蒜客---最大质因数
    JustOj 2009: P1016 (dp)
  • 原文地址:https://www.cnblogs.com/hongdada/p/6057370.html
Copyright © 2011-2022 走看看