1.main线程中先调用threadA.join() ,再调用threadB.join()实现A->B->main线程的执行顺序
调用threadA.join()时,main线程会挂起,等待threadA执行完毕返回后再执行,到执行threadB.join()时再挂起,待threadB执行完毕返回继续执行main
使用场景:线程B依赖线程A的计算结果的场景
package concurrency; public class JoinTest { public static void main(String[] args) throws InterruptedException{ Thread threadA = new Thread(new JoinJob(),"thread-A"); Thread threadB = new Thread(new JoinJob(),"thread-B"); threadB.start(); threadA.start(); threadA.join(); threadB.join(); System.out.println("main ending..."); } } class JoinJob implements Runnable{ @Override public void run() { System.err.println(Thread.currentThread().getName() + " starting..."); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " ending..."); } }
运行结果
2.CountDownLatch
使用场景:多线程数据计算时需要先分几个线程计算第一步骤的数据,再合并一个线程计算第二步
1 package concurrency; 2 3 import java.util.concurrent.CountDownLatch; 4 5 public class CountDownLatchTest { 6 static CountDownLatch c = new CountDownLatch(6);//如果count大于实际线程数,c.await()会一直等待 7 8 public static void main(String[] args) throws InterruptedException{ 9 for (int i = 0; i < c.getCount()/2; i++) { 10 new Thread(new CountDownJob(c)).start(); 11 new Thread(new CountDownLatchJob2(c)).start(); 12 13 } 14 15 System.out.println("waiting " + c.getCount() + " subthread doing"); 16 c.await();//await()会等待c的count值为0,才继续往下执行 17 System.out.println("all subthread done!"); 18 System.out.println(Thread.currentThread().getName() + " done!"); 19 } 20 } 21 22 class CountDownJob implements Runnable{ 23 CountDownLatch cDownLatch; 24 25 public CountDownJob(CountDownLatch cDownLatch) { 26 super(); 27 this.cDownLatch = cDownLatch; 28 } 29 30 @Override 31 public void run() { 32 try { 33 System.out.println(Thread.currentThread().getName() + " is doing something..."); 34 Thread.sleep(3000); 35 cDownLatch.countDown();//线程结束时cDownLatch-1 36 } catch (InterruptedException e) { 37 e.printStackTrace(); 38 } 39 40 } 41 42 } 43 class CountDownLatchJob2 implements Runnable{ 44 CountDownLatch cDownLatch; 45 46 public CountDownLatchJob2(CountDownLatch cDownLatch) { 47 super(); 48 this.cDownLatch = cDownLatch; 49 } 50 @Override 51 public void run() { 52 try { 53 Thread.sleep(1000); 54 } catch (InterruptedException e) { 55 System.err.println("thread sleep exception"); 56 } 57 System.out.println(Thread.currentThread().getName() + " is doing something"); 58 cDownLatch.countDown();//线程结束时cDownLatch-1 59 } 60 61 }
运行结果:
3.可循环使用的同步屏障CyclicBarrier
使用场景:多线程计算数据,等待全部线程执行完阶段一的工作之后,再执行后面的阶段工作
1 package concurrency; 2 3 import java.util.concurrent.BrokenBarrierException; 4 import java.util.concurrent.CyclicBarrier; 5 6 public class CyclicBarrierTest { 7 public static void main(String[] args) throws InterruptedException, BrokenBarrierException{ 8 CyclicBarrier cBarrier = new CyclicBarrier(6); 9 //CyclicBarrier 提供另一个构造函数传入所有线程执行完后需要执行的runnable 10 // CyclicBarrier cBarrier = new CyclicBarrier(6, new Runnable() { 11 // 12 // @Override 13 // public void run() { 14 // System.out.println("doing something after all threads done."); 15 // } 16 // }); 17 for (int i = 0; i < cBarrier.getParties()/2; i++) { 18 new Thread(new CyclicBarrierJob1(cBarrier)).start(); 19 new Thread(new CyclicBarrierJob2(cBarrier)).start(); 20 } 21 //CyclicBarrier 可以重置再次使用,如计算发生错误时可以重置计数器,并让线程重新执行一次。 22 //而CountDownLatch只可以使用一次 23 //cBarrier.reset(); 24 } 25 } 26 27 class CyclicBarrierJob1 implements Runnable { 28 CyclicBarrier cBarrier; 29 30 public CyclicBarrierJob1(CyclicBarrier cBarrier) { 31 super(); 32 this.cBarrier = cBarrier; 33 } 34 35 public void run() { 36 System.out.println(Thread.currentThread().getName() + " finished phase1"); 37 try { 38 cBarrier.await();//执行完阶段1的工作之后,等待其他线程全部执行完阶段1,才会继续执行阶段二 39 } catch (InterruptedException e) { 40 System.err.println("interrupted!"); 41 } catch (BrokenBarrierException e) { 42 System.err.println("broken barrier!"); 43 } 44 45 System.out.println(Thread.currentThread().getName() + " start phase2"); 46 } 47 } 48 class CyclicBarrierJob2 implements Runnable { 49 CyclicBarrier cBarrier; 50 51 public CyclicBarrierJob2(CyclicBarrier cBarrier) { 52 super(); 53 this.cBarrier = cBarrier; 54 } 55 56 public void run() { 57 System.out.println(Thread.currentThread().getName() + " finished phase1"); 58 try { 59 cBarrier.await();//执行完阶段1的工作之后,等待其他线程全部执行完阶段1,才会继续执行阶段二 60 } catch (InterruptedException e) { 61 System.err.println("interrupted!"); 62 } catch (BrokenBarrierException e) { 63 System.err.println("broken barrier!"); 64 } 65 System.out.println(Thread.currentThread().getName() + " start phase2"); 66 67 } 68 }
执行结果:
4.可控制并发线程数的信号量Semaphore
使用场景:控制同时访问特定资源的线程数量
1 package concurrency; 2 3 import java.util.concurrent.Semaphore; 4 5 public class SemaphoreTest { 6 public static void main(String[] args) { 7 final Semaphore semaphore = new Semaphore(3);//限制可以同时访问资源的线程数是10个 8 9 for (int i = 0; i < 12; i++) {//新建30个线程 10 new Thread(new Runnable() { 11 12 @Override 13 public void run() { 14 try { 15 semaphore.acquire();//获取到许可证才可以访问资源 16 System.out.println("accessing the database .."); 17 Thread.sleep(3000); 18 semaphore.release();//资源访问结束之后释放许可证 19 } catch (InterruptedException e) { 20 System.out.println("interrupted!"); 21 } 22 23 } 24 }).start(); 25 } 26 27 } 28 }