zoukankan      html  css  js  c++  java
  • ReentranLock

    Reentrantlock

    • JDK1.5新增的ReentrantLock类,重入锁。

    • ReentrantLock是独占锁且可重入的

    ReentrantLock和synchronized

    相同点:

    1. ReentrantLock和synchronized都是独占锁,只允许线程互斥的访问临界区

    2. ReentrantLock和synchronized都是可重入的

    不同点:

    1. synchronized加锁解锁的过程是隐式的,用户不用手动操作,优点是操作简单,但显得不够灵活;ReentrantLock需要手动加锁和解锁,且解锁的操作尽量要放在finally代码块中,保证线程正确释放锁。ReentrantLock操作较为复杂,但是因为可以手动控制加锁和解锁过程,在复杂的并发场景中能派上用场。

    2. ReentrantLock和synchronized都是可重入的。

      • synchronized因为可重入,因此可以放在被递归执行的方法上,且不用担心线程最后能否正确释放锁;

      • 而ReentrantLock在重入时要确保重复获取锁的次数必须和重复释放锁的次数一样,否则可能导致其他线程无法获得该锁。

    3. ReentrantLock可以实现公平锁

      • 公平锁是指当锁可用时,在锁上等待时间最长的线程将获得锁的使用权。而非公平锁则随机分配这种使用权。

      • 和synchronized一样,默认的ReentrantLock实现是非公平锁,因为相比公平锁,非公平锁性能更好。当然公平锁能防止饥饿,某些情况下也很有用。

      • 在创建ReentrantLock的时候通过传进参数true创建公平锁,如果传入的是false或没传参数则创建的是非公平锁

        ReentrantLock lock = new ReentrantLock(true);
    4. ReentrantLock可响应中断

      • 当使用synchronized实现锁时,阻塞在锁上的线程除非获得锁否则将一直等待下去,也就是说这种无限等待获取锁的行为无法被中断

      • 而ReentrantLock提供了一个可以响应中断的获取锁的方法lockInterruptibly()。该方法可以用来解决死锁问题

    5. 获取锁时限时等待

      ReentrantLock还提供了获取锁限时等待的方法tryLock(),可以选择传入时间参数,表示等待指定的时间,无参则表示立即返回锁申请的结果:true表示获取锁成功,false表示获取锁失败。可以使用该方法配合失败重试机制来更好的解决死锁问题。

    ReentrantLock实现同步

    package ReentrantLockTest;
    ​
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    ​
    //ReentrantLock实现同步
    public class ReenTrantTest1 {
        public static void main(String[] args) {
            Service service = new Service();
    ​
            MyThread t1 = new MyThread(service);
            MyThread t2 = new MyThread(service);
            MyThread t3 = new MyThread(service);
            MyThread t4 = new MyThread(service);
            MyThread t5 = new MyThread(service);
            t1.start();
            t2.start();
            t3.start();
            t4.start();
            t5.start();
        }
    ​
    }
    class Service {
        private Lock lock= new ReentrantLock();
        public void testMethod(){
            lock.lock();//获取锁
            for(int i=0;i<5;i++){
                System.out.println("ThreadName="+Thread.currentThread().getName()+" "+(i+1));
    ​
            }
            lock.unlock();//释放锁
        }
    }
    class MyThread extends Thread{
        private Service service;
        public MyThread(Service service){
            this.service=service;
        }
    ​
        @Override
        public void run() {
            service.testMethod();
        }
    }
    /*
    ThreadName=Thread-0 1
    ThreadName=Thread-0 2
    ThreadName=Thread-0 3
    ThreadName=Thread-0 4
    ThreadName=Thread-0 5
    ThreadName=Thread-1 1
    ThreadName=Thread-1 2
    ThreadName=Thread-1 3
    ThreadName=Thread-1 4
    ThreadName=Thread-1 5
    ThreadName=Thread-2 1
    ThreadName=Thread-2 2
    ThreadName=Thread-2 3
    ThreadName=Thread-2 4
    ThreadName=Thread-2 5
    ThreadName=Thread-3 1
    ThreadName=Thread-3 2
    ThreadName=Thread-3 3
    ThreadName=Thread-3 4
    ThreadName=Thread-3 5
    ThreadName=Thread-4 1
    ThreadName=Thread-4 2
    ThreadName=Thread-4 3
    ThreadName=Thread-4 4
    ThreadName=Thread-4 5
     */
    

      

    ReentrantLock结合Condition的await()、signal()实现有选择的wait()/notify()功能

    package ReentrantLockTest;
    ​
    import java.util.concurrent.locks.*;
    ​
    //ReentrantLock结合Condition的await()、signal()实现有选择的wait()/notify()功能
    public class ReentrantLock_Condition {
        public static void main(String[] args) {
            Service1 service1 = new Service1();
            AThread t1 = new AThread(service1);
            BThread t2 = new BThread(service1);
            t1.start();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            t2.start();
        }
    }
    class Service1{
        private Lock lcok=new ReentrantLock();
        private Condition condition=lcok.newCondition();
        public void await(){
            try {
                lcok.lock();
                System.out.println("await时间为:"+System.currentTimeMillis());
                condition.await();
                System.out.println("...await之后的语句会在signal执行之后继续执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lcok.unlock();
            }
        }
        public void signal(){
            try {
                lcok.lock();
                System.out.println("signal的时间为:"+System.currentTimeMillis());
                condition.signal();
            } finally {
                lcok.unlock();
            }
        }
    }
    class AThread extends Thread{
        private Service1 service1;
        public AThread(Service1 service1){
            this.service1=service1;
        }
    ​
        @Override
        public void run() {
            service1.await();
        }
    }
    class BThread extends Thread{
        private Service1 service1;
        public BThread(Service1 service1){
            this.service1=service1;
        }
    ​
        @Override
        public void run() {
            service1.signal();
        }
    }
    

      

    Unsafe

    执行await()方法实现线程的暂停运行的原理是:并发包源代码内部执行了 Unsafe 类的public native void park(boolean isAbsoult, long time);

    public native void park(boolean isAbsoult, long time);

    http://cnblogs.com/throwable/p/9139947.html

    http://blog.csdn.net/sinat_27593959/article/details/103637818

    可以通过反射的方式来创建一个实例来:

    Field field = Unsafe.class.getDeclaredField("theUnsafe");
    field.setAccessible(true);
    Unsafe unsafe = (Unsafe) field.get(null);

    通过这个Unsafe实例,可以进行内存管理、线程挂起和恢复、多线程同步、内存屏障等

    使用多个Condition可以实现堆指定线程的唤醒

    package ReentrantLockTest;
    ​
    import java.util.concurrent.locks.*;
    ​
    //ReentrantLock结合Condition的await()、signal()实现有选择的wait()/notify()功能
    public class ReentrantLock_Condition {
        public static void main(String[] args) {
            Service1 service1 = new Service1();
            AThread t1 = new AThread(service1);
            BThread t2 = new BThread(service1);
            t1.start();
            t2.start();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            service1.signalA();
        }
    }
    class Service1{
        private Lock lcok=new ReentrantLock();
        private Condition conditionA=lcok.newCondition();
        private Condition conditionB=lcok.newCondition();
        public void awaitA(){
            try {
                lcok.lock();
                System.out.println(Thread.currentThread().getName()+"await时间为:"+System.currentTimeMillis());
                conditionA.await();
                System.out.println(Thread.currentThread().getName()+"...await之后的语句会在signal执行之后继续执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lcok.unlock();
            }
        }
        public void awaitB(){
            try {
                lcok.lock();
                System.out.println(Thread.currentThread().getName()+"await时间为:"+System.currentTimeMillis());
                conditionB.await();
                System.out.println(Thread.currentThread().getName()+"...await之后的语句会在signal执行之后继续执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lcok.unlock();
            }
        }
        public void signalA(){
            try {
                lcok.lock();
                System.out.println("signal的时间为:"+System.currentTimeMillis());
                conditionA.signalAll();
            } finally {
                lcok.unlock();
            }
        }
        public void signalB(){
            try {
                lcok.lock();
                System.out.println("signal的时间为:"+System.currentTimeMillis());
                conditionB.signalAll();
            } finally {
                lcok.unlock();
            }
        }
    }
    class AThread extends Thread{
        private Service1 service1;
        public AThread(Service1 service1){
            this.service1=service1;
        }
    ​
        @Override
        public void run() {
            service1.awaitA();
        }
    }
    class BThread extends Thread{
        private Service1 service1;
        public BThread(Service1 service1){
            this.service1=service1;
        }
    ​
        @Override
        public void run() {
            service1.awaitB();
        }
    }
    /*
    Thread-0await时间为:1609579565800
    Thread-1await时间为:1609579565801
    signal的时间为:1609579566297
    Thread-0...await之后的语句会在signal执行之后继续执行//只唤醒了A线程
     */
    

      

    实现生产者/消费者多对多交替输出

     

    可能会出现死锁

    package ReentrantLockTest;
    ​
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    ​
    //使用ReentrantLock和Condition实现生产者/消费者多对多交替输出
    public class AlternateTest {
        public static void main(String[] args) {
            Service2 service2 = new Service2();
            setThread[] setThread = new setThread[10];
            getThread[] getThread = new getThread[10];
            for(int i=0;i<10;i++){
                setThread[i]=new setThread(service2);
                getThread[i]=new getThread(service2);
                setThread[i].start();
                getThread[i].start();
    ​
            }
    ​
        }
    ​
    }
    class Service2 {
        private Lock lock=new ReentrantLock();
        private Condition condition=lock.newCondition();
        private boolean hasValue=false;
        public void set(){
            try {
                lock.lock();
                if(hasValue==true){
                    condition.await();
                }
                System.out.println("生产:★");
                hasValue=true;
                condition.signalAll();
               //condition.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        public void get(){
            try {
                lock.lock();
                if(hasValue==false){
                    condition.await();
                }
                System.out.println("消耗:⭐");
                hasValue=false;
                condition.signalAll();//其实也会出现死锁??
                //condition.signal();//出现死锁
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
    class getThread extends Thread{
        private Service2 service2;
        public getThread(Service2 service2){
            this.service2=service2;
        }
    ​
        @Override
        public void run() {
            service2.get();
        }
    }
    class setThread extends Thread{
        private Service2 service2;
        public setThread(Service2 service2){
            this.service2=service2;
        }
    ​
        @Override
        public void run() {
            service2.set();
        }
    }

     实现线程的交替打印

    package Alternate;
    ​
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    ​
    //实现线程的交替执行
    public class AlternateExe {
        public static void main(String[] args) {
            Service service = new Service();
            for(int i=0;i<5;i++){
                MyThread3 t3 = new MyThread3(service);
                MyThread2 t2 = new MyThread2(service);
                MyThread1 t1 = new MyThread1(service);
                t1.start();
                t2.start();
                t3.start();
    ​
            }
        }
    }
    class Service{
       private Lock lcok= new ReentrantLock();
       private Condition condition=lcok.newCondition();
    ​
      volatile private int nextWhoPrint=1;//volatile可以省略
    public void test1(){
           try {
               lcok.lock();
               while(nextWhoPrint!=1)
                   condition.await();
               System.out.println("AAA");
               nextWhoPrint=2;
               condition.signalAll();
           } catch (InterruptedException e) {
               e.printStackTrace();
           } finally {
               lcok.unlock();
           }
    ​
       }
       public void test2(){
           try {
               lcok.lock();
               while(nextWhoPrint!=2)
                   condition.await();
               System.out.println("BBB");
               nextWhoPrint=3;
               condition.signalAll();
           } catch (InterruptedException e) {
               e.printStackTrace();
           } finally {
               lcok.unlock();
           }
    ​
       }
       public void test3(){
           try {
               lcok.lock();
               while(nextWhoPrint!=3)
                   condition.await();
               System.out.println("CCC");
               nextWhoPrint=1;
               condition.signalAll();
           } catch (InterruptedException e) {
               e.printStackTrace();
           } finally {
               lcok.unlock();
           }
       }
    }
    class MyThread1 extends Thread{
        private Service service;
        public MyThread1(Service service){
            this.service=service;
        }
    ​
        @Override
        public void run() {
            service.test1();
        }
    }
    class MyThread2 extends Thread{
        private Service service;
        public MyThread2(Service service){
            this.service=service;
        }
    ​
        @Override
        public void run() {
            service.test2();
        }
    }
    class MyThread3 extends Thread{
        private Service service;
        public MyThread3(Service service){
            this.service=service;
        }
    ​
        @Override
        public void run() {
            service.test3();
        }
    }
    /*
    AAA
    BBB
    CCC
    AAA
    BBB
    CCC
    AAA
    BBB
    CCC
    AAA
    BBB
    CCC
    AAA
    BBB
    CCC
    */

     

  • 相关阅读:
    h.264的POC计算(转载)
    如何从kernel源码中查出版本号(转载)
    git切换分支保存修改的代码的方法(转载)
    【转载】Gradle for Android 第二篇( Build.gradle入门 )
    【转】gradle for android 第一篇
    android studio学习----android studio断点调试
    maven 学习---Maven配置之pom文件配置包含和排除测试
    maven 学习---Maven 编译打包时如何忽略测试用例
    android studio学习----gradle多渠道打包
    android studio学习----gradle命令详解
  • 原文地址:https://www.cnblogs.com/learnjavajava/p/14520417.html
Copyright © 2011-2022 走看看