• 多线程的Lock锁——ReentrantLock


    在Java多线程中,可以使用synchronized关键字来实现线程之间的同步互斥,但在JDK1.5中新增了Lock锁,同样可以实现同样的效果,并且扩展功能上也更加强大,比如嗅探锁定、多路分支通知等功能,而且使用上也更灵活。

            Lock锁分为两类:ReentrantLock和ReentrantReadWriteLock。

    这里介绍ReentrantLock类的基础用法。

            ReentrantLock具有完全的排他性效果,即同一时刻只有一个线程拥有Lock对象锁。

            一个ReentrantLock对象可以创建多个Condition对象,可以根据不同的Condition,进行针对唤醒和等待Lock锁。

    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
     
    lock.lock();
    .
    .//需要同步的代码
    .
    lock.unlock();
     
    condition.await();//进入等待状态,释放lock锁
    condition.signal();//随机唤醒一个等待lock锁的线程
    condition.signalAll();//唤醒所有condition条件下等待lock的线程

    具体例子一(一对一生产与消费):

    1、创建一个服务类,

    package com.cjs.ConditionTestMantToMany;
     
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
     
    public class MyService {
        private Lock lock = new ReentrantLock();
        private Condition condition = lock.newCondition();
        private boolean hasValue;//判断是否有值
     
        public void set() {
            try {
                lock.lock();
                while (hasValue == true) {
                    condition.await();//进入等待,相当于wait()
                }
                System.out.println("set Print");
                hasValue = true;
                condition.signalAll();//唤醒所有正在等待的线程,相当于notifiAll()
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
     
        public void get() {
            try {
                lock.lock();
                while (hasValue == false) {
                    condition.await();//进入等待,相当于wait()
                }
                System.out.println("get Print");
                hasValue = false;
                condition.signalAll();//唤醒所有正在等待的线程,相当于notifiAll()
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
     
        }
    }

    2、创建两个线程类,调用服务类的方法,

    package com.cjs.ConditionTest;
     
    public class MyThreadA extends Thread {
        private MyService myService;
     
        public MyThreadA(MyService myService) {
            this.myService = myService;
        }
     
        @Override
        public void run() {
            for (int i=0; i<100;i++) {
                myService.set();
            }
        }
    }
    package com.cjs.ConditionTest;
     
    public class MyThreadB extends Thread {
        private MyService myService;
     
        public MyThreadB(MyService myService) {
            this.myService = myService;
        }
     
        @Override
        public void run() {
            for (int i=0; i<100;i++) {
                myService.get();
            }
        }
    }

    3、创建Main类,用来启动程序,

    package com.cjs.ConditionTest;
     
    public class Run {
        public static void main(String[] args) {
            MyService myService = new MyService();
            MyThreadA a = new MyThreadA(myService);
            a.start();
            MyThreadB b = new MyThreadB(myService);
            b.start();
        }
    }

    4、运行,查看控制台,get和set是交替打印,即一方面证明生产与消费属于一对一关系,另一方面说明ReentrantLock是互斥的。

    具体例子二(多Condition条件的使用)

    1、创建一个服务类

    package com.cjs.MustUseMoreCondition_OK;
     
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
     
    public class MyService {
        private Lock lock = new ReentrantLock();
        public Condition conditionA = lock.newCondition();
        public Condition conditionB = lock.newCondition();
     
        public void awaitA() {
            try {
                lock.lock();
                System.out.println("begin awaitA时间为:"+ System.currentTimeMillis() + "ThreadName=" + Thread.currentThread().getName());
                conditionA.await();
                System.out.println("end awaitA时间为:"+System.currentTimeMillis()+"ThreadName=" + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
        public void awaitB() {
            try {
                lock.lock();
                System.out.println("begin awaitB时间为:"+ System.currentTimeMillis() + ", ThreadName=" + Thread.currentThread().getName());
                conditionB.await();
                System.out.println("end awaitB时间为:"+System.currentTimeMillis()+", ThreadName=" + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
     
        public void signalAll_A() {
            try {
                lock.lock();
                System.out.println("signalAll_A时间为:" + System.currentTimeMillis() + ", ThreadName=" + Thread.currentThread().getName());
                conditionA.signalAll();
            } finally {
                lock.unlock();
            }
        }
        public void signalAll_B() {
            try {
                lock.lock();
                System.out.println("signalAll_B时间为:" + System.currentTimeMillis() + ", ThreadName=" + Thread.currentThread().getName());
                conditionB.signalAll();
            } finally {
                lock.unlock();
            }
        }
    }

    这里创建了两个Condition对象,分别是conditionA和conditionB。

    2、创建两个线程类

    package com.cjs.MustUseMoreCondition_OK;
     
    public class ThreadA extends Thread {
        private MyService myService;
     
        public ThreadA(MyService myService) {
            this.myService = myService;
        }
     
        @Override
        public void run() {
            myService.awaitA();
        }
    }
    package com.cjs.MustUseMoreCondition_OK;
     
    public class ThreadB extends Thread {
        private MyService myService;
     
        public ThreadB(MyService myService) {
            this.myService = myService;
        }
     
        @Override
        public void run() {
            myService.awaitB();
        }
    }

    3、创建一个Main类,

    package com.cjs.MustUseMoreCondition_OK;
     
    public class Run {
        public static void main(String[] args) {
            try {
                MyService myService = new MyService();
                ThreadA a = new ThreadA(myService);
                a.setName("A");
                a.start();
                ThreadB b = new ThreadB(myService);
                b.setName("B");
                b.start();
                Thread.sleep(3000);
                myService.signalAll_A();
                //myService.signalAll_B();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    上面注释了myService.signalAll_B();表示不换醒conditionB条件的线程。

    4、运行程序

     

     运行结果中,只有conditionA的线程被唤醒,同时执行结束;但是程序并没有结束,还有红色的方框显示出来,说明还有其他线程正在等待,这些等待的线程就是conditionB条件的线程。这时去掉myService.signalAll_B();前面的注释,再运行一次程序。

            另外补充,ReentranrLock类还有两种锁,分别是:公平锁和非公平锁

    1、公平锁:Lock  lock = new ReentrantLock(true);

    表示获取锁的顺序是几乎按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。

    2、非公平锁:Lock  lock = new ReentrantLock(false);

    表示一种获取锁的抢占机制,就是随机获取锁。

     

  • 相关阅读:
    powerdesigner添加mysql的字符集ENGINE和DEFAULT CHARACTER SET
    powerdesigner怎么设置同时显示name和code
    更改gradle的java的class文件输出目录的结构
    使用TortoiseGit时如何实现SSH免密码登录
    TortoiseGit之配置密钥
    Mock InjectMocks ( @Mock 和 @InjectMocks )区别
    Centos tomcat jmx 远程连接
    【C++】常见易犯错误之数值类型取值溢出与截断(3)
    【C++】常见易犯错误之数值类型取值溢出与截断(2)
    【C++】常见易犯错误之数值类型取值溢出与截断(1)
  • 原文地址:https://www.cnblogs.com/SysoCjs/p/10319484.html
Copyright © 2020-2023  润新知