并发容器中常用的同步组件

CountDownLatch

通过计数来保证线程是否需要一直阻塞。

public class CountDownLatchExample {
    private static int threadCount = 200;
    public static void main(String[] args) throws InterruptedException {
        ExecutorService exec = Executors.newCachedThreadPool();
        final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
        for (int i=0; i<threadCount; i++) {
            final int threadNum = i;
            exec.execute(()->{
                try {
                    test(threadNum);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        countDownLatch.await();
        System.out.println("finish");
        exec.shutdown();
    }

    private static void test(int threadNum) throws InterruptedException {
	    Thread.sleep(10);
        System.out.println("thread number: " + threadNum);
    }
}
Semaphore

信号量,可以控制并发访问的线程个数,控制某个资源被同时访问的个数,常用于仅能提供有限访问的资源。下面代码中的任务,只有大约30个线程中的任务会被执行,其余因为等待超时被丢弃。

public class SemaphoreExample1 {
	// 并发线程数
   private static int threadCount = 200;
   public static void main(String[] args) {
   	// 线程池
       final ExecutorService exec = Executors.newCachedThreadPool();
       // 声明信号量10个,表示控制并发访问线程数为10。
       final Semaphore semaphore = new Semaphore(10);
       for (int i=0; i<threadCount; i++) {
           final int threadNum = i;
           exec.execute(()->{
               try {
               		// 尝试获取信号量,获取不到等待30ms,等待后获取不到则丢弃任务
                   if(semaphore.tryAcquire(30, TimeUnit.MILLISECONDS)) {
                       test(threadNum);
                       // 释放信号量
                       semaphore.release();
                   }
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           });
       }
       exec.shutdown();
   }

   private static void test(int threadNum) throws InterruptedException {
       System.out.println(Thread No.: " +threadNum);
       Thread.sleep(10);
   }
}
CyclicBarrier

多个线程互相等待。在涉及固定线程数、这些线程必须彼此等待时,使用CyclicBarrier。之所以成为cyclic,是因为它可以reset后重新计数。

public class CyclicBarrierExample3 {
    // 线程到达屏障时,优先执行runnable。
    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5, ()->{
        System.out.println("callback is running.");
    });

    public static void main(String[] args) throws InterruptedException {
        ExecutorService exec = Executors.newCachedThreadPool();
        int threadCount = 10;
        for (int i=0; i<threadCount; i++) {
            final int threadNum = i;
            Thread.sleep(1000);
            exec.execute(()->{
                try {
                    race(threadNum);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                } catch (TimeoutException e) {
                    e.printStackTrace();
                }
            });
        }
        exec.shutdown();
    }

    private static void race(int threadNum) throws InterruptedException, BrokenBarrierException, TimeoutException {
        Thread.sleep(1000);
        System.out.println("Thread "+ threadNum + " is ready");
        cyclicBarrier.await();
        System.out.println("Thread "+ threadNum + " continue.");
    }
}
ReentrantLock

和synchronized具有类似的属性和性能,但使用时比synchronize复杂,使用不当会造成死锁。仅在需要ReentrantLock的独有功能时,才推荐使用。
ReentrantLock的独有功能:

  1. 可指定是公平锁还是非公平锁。
  2. 提供了一个Condition类,可以分组唤醒需要唤醒的线程。
  3. 提供能够中断等待锁的线程的机制,lock.lockInterruptibly()。
Future

通过Thread和Runnable创建的线程,在执行完成后无法获得执行结果。通过Callable、Future和FutureTask可以获得线程执行结果。
使用Future获取线程执行结果:

public class FutureExample {
    static class MyCallable implements Callable<String> {
        @Override
        public String call() throws InterruptedException {
            System.out.println("do something in MyCallable");
            Thread.sleep(5000);
            return "Done";
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService exec = Executors.newCachedThreadPool();
        Future<String> future = exec.submit(new MyCallable());
        System.out.println("do something in main");
        System.out.println("thread result: " + future.get());
    }
}

使用FutureTask获取线程执行结果,更简单:

public class FutureTaskExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService exec = Executors.newCachedThreadPool();
        FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("do something in myCallable");
                Thread.sleep(5000);
                return "Done";
            }
        });
        new Thread(futureTask).start();
        System.out.println("do something in main");
        System.out.println("thread result: " + futureTask.get());
    }
}
BlockingQueue

阻塞队列提供了四套方法进行插入、删除和检测,对不能立刻执行会有不同的反应。

TypeThrow ExceptionSpecial ValueBlocksTimes Out
Insertadd(o)offer(o)put(o)offer(o, timeout, timeunit)
Removeremove(o)poll(o)take(o)poll(o, timeout, timeunit)
Checkelement(o)peek(o)
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值