zoukankan      html  css  js  c++  java
  • 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();
            }
        }
    }
  • 相关阅读:
    POJ 3140 Contestants Division (树dp)
    POJ 3107 Godfather (树重心)
    POJ 1655 Balancing Act (树的重心)
    HDU 3534 Tree (经典树形dp)
    HDU 1561 The more, The Better (树形dp)
    HDU 1011 Starship Troopers (树dp)
    Light oj 1085
    Light oj 1013
    Light oj 1134
    FZU 2224 An exciting GCD problem(GCD种类预处理+树状数组维护)同hdu5869
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/5894986.html
Copyright © 2011-2022 走看看