线程同步辅助类全攻略
一.控制并发访问资源的利器-信号量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对象,以进行其他操作。