美文网首页
concurrent包的同步控制工具

concurrent包的同步控制工具

作者: 江江的大猪 | 来源:发表于2017-11-06 20:24 被阅读25次

    ReentrantLock

    可重入锁,应用层面的锁,jdk6后性能和synchronized差不多,但是有更多的功能。

    • 可以响应线程中断:
        ReentrantLock lock = new ReentrantLock();
        try {
            lock.lockInterruptibly();
        } catch (InterruptedException e) {
    
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    
    • 可以限时,这样可以避免死锁
           ReentrantLock lock = new ReentrantLock();
            try {
                if (lock.tryLock(5, TimeUnit.SECONDS)) {
    
                } else {
                
                }
            } catch (InterruptedException e) {
    
            } finally {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
    
    • ReentrantLock可以实现公平锁:

    ReentrantLock lock = new ReentrantLock(true);

    • 通过Condition类来挂起唤醒线程,condition和Object的wait和notify很像
      Condition condition = lock.newCondition();  
      condition.await();  
      condition.await(等待时间);  
      condition.awaitUninterruptibly();  
      condition.signal();  
      condition.signalAll();
    

    Semaphore信号量

    信号量可以看做共享锁,允许多个线程进入临界区

    • acquire()
    • acquireUninterruptibly()
    • tryacquire()、tryacquire(long,TimeUnit)
    • release()
        Semaphore semaphore = new Semaphore(5);
        try {
            semaphore.acquire();
        } catch (InterruptedException e) {
        
        } finally {
            semaphore.release();
        }
    

    ReadWriteLock读写锁

    jdk5提供的一种读写分离的锁,有使用写锁的线程竞争锁才会加锁

    • readLock()获得ReentrantReadWriteLock.ReadLock对象
    • writeLock()获得ReentrantReadWriteLock.WriteLock对象
        ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        Lock readLock = readWriteLock.readLock();
        Lock writeLock = readWriteLock.writeLock();
        readLock.lock();//读锁和写锁的使用和ReentrantLock一样: 
        writeLock.lock();
    

    CountDownLatch倒数计时器

    使用CountDownLatch将主线程挂起,准备工作完毕唤醒主线程

    public class CountDownLatchDemo implements Runnable{
        private static CountDownLatch latch = new CountDownLatch(5);
        
        @Override
        public void run() {
            //一些检查工作,做完之后倒数计数器减一
            latch.countDown();
        }
    
        public static void main(String[] args) throws InterruptedException {
            ExecutorService exec = Executors.newFixedThreadPool(5);
            for (int i = 0; i < 5; i++) {
                exec.submit(new CountDownLatchDemo());
            }
            latch.await();//五个检查工作都完成才会继续执行
        }
    }
    

    CyclicBarrier循环栅栏

    和CountDownLatch很像,只不过这计数器可以重复使用,比如将计数器设为10,执行完一批十个线程后,计数器就会归零,然后凑齐下一批十个线程。
    CountDownLatch是一个线程等待多个线程,CyclicBarrier可以多个线程间相互等待,而且可以复用,功能更强。

    • 构造方法:CyclicBarrier(int parties, Runnable barrierAction)

    parties是计数器的数,barrierAction是计数器归零后执行的线程(回调线程)

    • await()

    每次调用await()的时候只有总共调用parties次await()才会继续向下执行

    public class BarrierDemo implements Runnable {
        int flag = 0;
        @Override
        public void run() {
            if (flag == 0) {
                //TODO
            } else {
                //TODO
            }
            flag++;
        }
        public static void main(String[] args) throws InterruptedException {
            CyclicBarrier barrier = new CyclicBarrier(10, new BarrierDemo());
            for (int i = 0; i < 10; i++) {
                new Thread(new Prepare(barrier)).start();
            }
            Thread.sleep(5000);
        }
    }
    class Prepare implements Runnable {
        CyclicBarrier barrier;
        public Prepare(CyclicBarrier barrier) {
            this.barrier = barrier;
        }
        @Override
    public void run() {
            try {
                barrier.await();//十个线程全部await之后,继续向下执行并触发barrier的执行线程,并清零计数器
                //TODO
                barrier.await();//复用计数器开始下一轮
                //TODO
            } catch (InterruptedException ie) {
    
            } catch (BrokenBarrierException be) {//有线程被中断后,其他的线程抛出该异常
    
            }
        }}
    

    LockSupport

    提供线程阻塞原语,jdk内部有很多东西都是用LockSupport实现的。suspend()方法已经被弃用,用这个工具挂起线程是最好的。类似于信号量,内部有一个许可,pack()拿到许可,unpack()申请许可。unpack()发生在pack()之前,pack()并不会阻塞线程,和suspend()不一样。
    当线程被中断时pack()会返回,线程继续执行,并不会抛出InterruptedException,pack()之后可以检测线程的中断标志位。

    • LockSupport.pack()

    挂起当前线程

    • LockSupport.unpack(Thread)

    恢复某个线程

    肥肥小浣熊

    相关文章

      网友评论

          本文标题:concurrent包的同步控制工具

          本文链接:https://www.haomeiwen.com/subject/vqkrmxtx.html