• Android ReentrantLock


    synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。 
    1.某个线程在等待一个锁的控制权的这段时间需要中断 
    2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程 
    3.具有公平锁功能,每个到来的线程都将排队等候 
    下面细细道来…… 

    先说第一种情况,ReentrantLock的lock机制有2种,忽略中断锁和响应中断锁,这给我们带来了很大的灵活性。比如:如果A、B2个线程去竞争锁,A线程得到了锁,B线程等待,但是A线程这个时候实在有太多事情要处理,就是一直不返回,B线程可能就会等不及了,想中断自己,不再等待这个锁了,转而处理其他事情。这个时候ReentrantLock就提供了2种机制,第一,B线程中断自己(或者别的线程中断它),但是ReentrantLock不去响应,继续让B线程等待,你再怎么中断,我全当耳边风(synchronized原语就是如此);第二,B线程中断自己(或者别的线程中断它),ReentrantLock处理了这个中断,并且不再等待这个锁的到来,完全放弃。(如果你没有了解java的中断机制,请参考下相关资料,再回头看这篇文章,80%的人根本没有真正理解什么是java的中断,呵呵) 

    这里来做个试验,首先搞一个Buffer类,它有读操作和写操作,为了不读到脏数据,写和读都需要加锁,我们先用synchronized原语来加锁,如下: 

    package cn.vicky.chapt10;
    
    /**
     *
     * @author Vicky.H
     */
    public class Buffer {
    
        private Object lock;
    
        public Buffer() {
            lock = this;
        }
    
        public void write() {
            synchronized (lock) {
                long startTime = System.currentTimeMillis();
                System.out.println("开始往这个buff写入数据…");
                for (;;)// 模拟要处理很长时间    
                {
                    if (System.currentTimeMillis()
                            - startTime > Integer.MAX_VALUE) {
                        break;
                    }
                }
                System.out.println("终于写完了");
            }
        }
    
        public void read() {
            synchronized (lock) {
                System.out.println("从这个buff读数据");
            }
        }
    
        public static void main(String[] args) {
            Buffer buff = new Buffer();
    
            final Writer writer = new Writer(buff);
            final Reader reader = new Reader(buff);
    
            writer.start();
            reader.start();
    
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    long start = System.currentTimeMillis();
                    for (;;) {
                        //等5秒钟去中断读    
                        if (System.currentTimeMillis()
                                - start > 5000) {
                            System.out.println("不等了,尝试中断");
                            reader.interrupt();
                            break;
                        }
    
                    }
    
                }
            }).start();
            // 我们期待“读”这个线程能退出等待锁,可是事与愿违,一旦读这个线程发现自己得不到锁,
            // 就一直开始等待了,就算它等死,也得不到锁,因为写线程要21亿秒才能完成 T_T ,即使我们中断它,
            // 它都不来响应下,看来真的要等死了。这个时候,ReentrantLock给了一种机制让我们来响应中断,
            // 让“读”能伸能屈,勇敢放弃对这个锁的等待。我们来改写Buffer这个类,就叫BufferInterruptibly吧,可中断缓存。
        }
    }
    
    class Writer extends Thread {
    
        private Buffer buff;
    
        public Writer(Buffer buff) {
            this.buff = buff;
        }
    
        @Override
        public void run() {
            buff.write();
        }
    }
    
    class Reader extends Thread {
    
        private Buffer buff;
    
        public Reader(Buffer buff) {
            this.buff = buff;
        }
    
        @Override
        public void run() {
    
            buff.read();//这里估计会一直阻塞    
    
            System.out.println("读结束");
    
        }
    }
    package cn.vicky.chapt10;
    
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     *
     * @author Vicky.H
     */
    public class BufferInterruptibly {
    
        private ReentrantLock lock = new ReentrantLock();
    
        public void write() {
            lock.lock();
            try {
                long startTime = System.currentTimeMillis();
                System.out.println("开始往这个buff写入数据…");
                for (;;)// 模拟要处理很长时间    
                {
                    if (System.currentTimeMillis()
                            - startTime > Integer.MAX_VALUE) {
                        break;
                    }
                }
                System.out.println("终于写完了");
            } finally {
                lock.unlock();
            }
        }
    
        public void read() throws InterruptedException {
            lock.lockInterruptibly();// 注意这里,可以响应中断    
            try {
                System.out.println("从这个buff读数据");
            } finally {
                lock.unlock();
            }
        }
    
        public static void main(String args[]) {
            BufferInterruptibly buff = new BufferInterruptibly();
    
            final Writer2 writer = new Writer2(buff);
            final Reader2 reader = new Reader2(buff);
    
            writer.start();
            reader.start();
    
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    long start = System.currentTimeMillis();
                    for (;;) {
                        if (System.currentTimeMillis()
                                - start > 5000) {
                            System.out.println("不等了,尝试中断");
                            reader.interrupt();
                            break;
                        }
                    }
                }
            }).start();
    
        }
    }
    
    class Reader2 extends Thread {
    
        private BufferInterruptibly buff;
    
        public Reader2(BufferInterruptibly buff) {
            this.buff = buff;
        }
    
        @Override
        public void run() {
    
            try {
                buff.read();//可以收到中断的异常,从而有效退出    
            } catch (InterruptedException e) {
                System.out.println("我不读了");
            }
    
            System.out.println("读结束");
    
        }
    }
    
    class Writer2 extends Thread {
    
        private BufferInterruptibly buff;
    
        public Writer2(BufferInterruptibly buff) {
            this.buff = buff;
        }
    
        @Override
        public void run() {
            buff.write();
        }
        
    }

    2个程序,运行结果:

    run:
    开始往这个buff写入数据…
    不等了,尝试中断 

    run:
    开始往这个buff写入数据…
    不等了,尝试中断
    我不读了
    读结束

    ‍ReentrantLock是一个互斥的同步器,其实现了接口Lock

    一个重要Example:

    package tags;
    
    import java.util.Calendar;
    
    public class TestLock {
        private ReentrantLock lock = null;
        
        public int data = 100;     // 用于线程同步访问的共享数据
    
        public TestLock() {
            lock = new ReentrantLock(); // 创建一个自由竞争的可重入锁
        }
        public ReentrantLock getLock() {
            return lock;
        }
        
        public void testReentry() {
            lock.lock();
            Calendar now = Calendar.getInstance();
            System.out.println(now.getTime() + " " + Thread.currentThread()    + " get lock.");
        }
    
        public static void main(String[] args) {
            TestLock tester = new TestLock();
    
            //1、测试可重入
            tester.testReentry();
            tester.testReentry(); // 能执行到这里而不阻塞,表示锁可重入
            tester.testReentry(); // 再次重入
    
            // 释放重入测试的锁,要按重入的数量解锁,否则其他线程无法获取该锁。
            tester.getLock().unlock();
            tester.getLock().unlock();
            tester.getLock().unlock();
    
            //2、测试互斥
            // 启动3个线程测试在锁保护下的共享数据data的访问
            new Thread(new workerThread(tester)).start();
            new Thread(new workerThread(tester)).start();
            new Thread(new workerThread(tester)).start();
        }
    
    
        // 线程调用的方法
        public void testRun() throws Exception {
            lock.lock();
    
            Calendar now = Calendar.getInstance();
            try {
                // 获取锁后显示 当前时间 当前调用线程 共享数据的值(并使共享数据 + 1)
                System.out.println(now.getTime() + " " + Thread.currentThread()+ " accesses the data " + data++);
                Thread.sleep(1000);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
    
    // 工作线程,调用TestServer.testRun
    class workerThread implements Runnable {
    
        private TestLock tester = null;
    
        public workerThread(TestLock testLock) {
            this.tester = testLock;
        }
    
        public void run() {
            try {
                tester.testRun();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
  • 相关阅读:
    现在分词和过去分词
    VMware Workstation Ubuntu 20.04 LTS无法连接网络问题
    Java中定时器Timer致命缺点(附学习方法)
    2020 年度编程语言排行榜出炉!C 语言称霸,Java 遭遇滑铁卢…….
    人工智能必备数学基础:线性代数基础(1)
    初学VBA
    何同学新视频火了!找到减少沉迷手机的最佳方法:附免费APP
    支付宝蚂蚁森林下线能量提醒功能 产品经理:被骂了、我改
    可抵御所有已知黑客攻击 中国组建天地一体化量子通信网络
    MYSQL数据库 增删改查基础语句
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/5894986.html
Copyright © 2020-2023  润新知