zoukankan      html  css  js  c++  java
  • 廖雪峰Java11多线程编程-3高级concurrent包-1ReentrantLock

    1.java.util.concurrent

    线程同步:

    • 是因为多线程读写竞争资源需要同步
    • Java语言提供了synchronized/wait/notify来实现同步
    • 编写多线程同步很困难

    所以Java提供了更高级的java.util.concurrent包:

    • 更高级的同步功能
    • 简化多线程程序的编写
    • JDK>= 1.5

    2.ReetrantLock

    java.util.locks.ReentrantLock用于替代synchronized加锁
    synchronized是Java语言层面提供的,不需考虑异常
    ReentrantLock是普通的Java类,要用try...finally来保证锁能够正确释放

    当我们使用ReenTrantLock的时候,我们首先要通过new ReentrantLock()新建一个Lock对象。然后我们先试图用lock()方法获得当前对象的锁。如果我们获得锁成功,就进入try代码,最后在finally中用unlock()来释放这个锁。
    注意:lock()方法必须在try代码之外完成。因为lock()可能会失败,而unlock()一定要在finally中完成。

    class Count{
        final Lock lock = new ReetrantLock(); //获得ReentrantLock对象
        public void inc(){
            lock.lock();    //获得当前对象的锁可能会失败,所以要放在try...finally外面
            try{
                n = n + 1;
            }finally{
                lock.unlock(); //释放锁
            }
    }
    

    ReentrantLock:

    • 可重入锁,一个线程可多次获取同一个锁
    • lock()方法可获取锁
    • tryLock()方法可尝试获取锁并可指定超时。
    class Counter{
        final Lock lock = new ReentrantLock();
        private void inc() throws InterruptedException{
            if(lock.tryLock(1, TimeUnit.SECONDS)){
                try{
                    n = n + 1;
                }finally {
                    lock.unlock();
                }
            }
        }
    }
    

    使用ReentrantLock比直接使用synchronized更安全,因为synchronized会导致线程要么获得锁,要的永远等待下去。而使用ReentrantLock的时候,我们通过tryLock()在失败的时候不会导致死锁。

    3.示例

    import java.util.concurrent.locks.ReentrantLock;
    import java.util.concurrent.locks.Lock;
    
    class Counter{
        private Lock lock = new ReentrantLock();
        private int value = 0;
        public void add(int m){
            lock.lock();
            try{
                value += m;
            }finally {
                lock.unlock();
            }
        }
        public void dec(int m){
            lock.lock();
            try{
                value -= m;
            }finally {
                lock.unlock();
            }
        }
        public int get(){
            lock.lock();
            try{
                return this.value;
            }finally {
                lock.unlock();
            }
        }
    }
    public class Main{
        final static int LOOP = 100;
        public static void main(String[] args) throws Exception{
            Counter counter = new Counter();
            Thread t1 = new Thread(){
                public void run(){
                    for(int i=0;i<LOOP;i++){
                        counter.add(1);
                    }
                }
            };
            Thread t2 = new Thread(){
                public void run(){
                    for(int i=0;i<LOOP;i++){
                        counter.dec(1);
                    }
                }
            };
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            System.out.println(counter.get());
        }
    }
    

    4.总结:

    • ReentrantLock可以替代synchronized
    • ReentrantLock获取锁更安全
    • lock()获取锁在try...finally之前
    • 必须使用try... finally保证释放锁
  • 相关阅读:
    android AutoCompleteTextView 自定义BaseAdapter
    svg矢量图绘制以及转换为Android可用的VectorDrawable资源
    div 自适应高度 自动填充剩余高度
    Android 禁止Viewpager左右滑动功能
    ant安装、环境变量配置及验证
    创建GitHub技术博客全攻略
    简单的Hibernate入门简介
    Java开发Maven环境配置和介绍
    Android 子activity关闭 向父activity传值
    github for windows 桌面版使用方法
  • 原文地址:https://www.cnblogs.com/csj2018/p/11007060.html
Copyright © 2011-2022 走看看