线程同步辅助类全攻略

一.控制并发访问资源的利器-信号量Semaphore

  1.定义及作用

    它是一种计数器,用来保护一个或多个共享资源的访问,计数器大于0表示可以使用资源,如果为0,线程会休眠到计数器大于0,线程完成资源使用后,信号量要被释放,释放会使计数器加一。

  2.使用方法

    1.首先调用acquire()方法获得信号量,计数器-1,然后操作资源,然后通过release()方法释放资源(一般在finally里面释放),信号量+1

    2.要注意一点,就是新建semaphore实例时,通过构造函数传进整型数据,指定总的信号量,比如传入3说明同一时间可以有三个线程去使用资源。

    3.它还有tryacquire方法,试图去获取信号量,如果能获取就返回true。

二.等待多个并发事件的完成-CountDownLatch

  1.定义和作用

    为了等待一组线程的完成,它可以等待。比如main线程里面等待,新建了五个线程在跑,完成一个计数器-1,为0时表示全部完成了,这时main线程继续工作。

  2.使用方法

    1.这是新建的五个线程,等待它们准备完毕,毕竟主线程在阻塞等待它们呢。

    

for(int i =0;i<5;i++){    
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    System.out.println("正在等待" + Thread.currentThread().getName());
                    Thread.sleep(3000);
                    System.out.println(Thread.currentThread().getName()
                            + "准备完毕");
                    Thread.sleep(1000);
                    countDownLatch.countDown();
                    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }).start();

        }

    2.主线程里面调用CountDownLatch的await方法等待那几个线程

try {
            System.out.println("还有五个人没准备好,我们等他们一下---");
            countDownLatch.await();
           
           System.out.println("ok,都准备好了,出发吧");
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

 

三.某个点上的线程同步-CyclicBarrier

  1.定义和作用

    它是当一个线程执行完了,就会调用await等待其他线程,然后+1,当加到指定的数,说明所有线程都已经到达啦,然后之前为了等待而沉睡的线程将继续执行下去。

  2.和CountDownLatch的区别

     CyclicBarrier:一组线程全部都到达某一个点后,再继续往下执行。比如说A到了广州,B,C没到,A会调用await等,计数器还+1表面有一个人到了,接着B,C到了之后,CyclicBarrier发现所有人都到了,就ABC继续执行下去,去深圳。

     CountDownLatch:一个线程,或者说调用了await的线程,会等待其他线程执行完了(每完一个计数器-1,为0时表示执行完了)才继续执行下去。比如说A去到了广州,调用了await方法等待,B,C说A啊,你等等我们,我们还在茂名,等我们到广州和你玩玩再走吧。A很无奈,只好等,等B,C到了广州之后(每到一个调用countDown方法-1),A很开心,那两条粉肠终于都到了呢,我接着去深圳happy吧。

  3.使用方法

    1.创建CyclicBarrier对象,设定总的线程数。

    CyclicBarrier cyclicBarrier = new CyclicBarrier(4);
        for(int i=0;i<4;i++){
            new MyTask(cyclicBarrier).start();
        }

 

    2.把CyclicBarrier对象传到具体的线程实现类,好进行等待操作,以及编写一些线程的业务。

     static class MyTask extends Thread{
        private CyclicBarrier cyclicBarrier;
        public MyTask(CyclicBarrier cyclicBarrier){
            this.cyclicBarrier = cyclicBarrier;
        }
        
        @Override
        public void run() {
            System.out.println("线程正在写入数据-------"+Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println("线程写入数据完毕-------"+Thread.currentThread().getName());
          //线程在此处等待 cyclicBarrier.await(); }
catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (BrokenBarrierException e) { // TODO Auto-generated catch block e.printStackTrace(); }
        //线程唤醒之后继续执行的业务 System.out.println(
"所有线程写入完毕,继续处理其他业务"+"这个是"+Thread.currentThread().getName()); } }

   3.CyclicBarrier还可以往构造器里面传Runnable对象,以进行其他操作。

posted @ 2018-11-06 16:11  AJimmyFang  阅读(270)  评论(0编辑  收藏  举报