【多线程】四个同步工具的使用

多线程系列三(同步工具类)

今天博客我总结了一下多线程中关于四个同步工具类的使用,每个同步工具类都有自己应用的场景,例如:

 

信号灯(Semaphore):

  应用场景:办公室里有一台打印机,只能让一个人来打印东西,如果别人来了就会被阻塞住,这个人打印完了才会让下一个人来继续打印,如果办公室里面多买了两台打印机,一共有三台打印机了,这样办公室里面就可以同时来三个人打印,再有多余的人才会被阻塞住,主要其中一台打印机空闲下来就会允许后面的人继续来打印。

示例代码:

package com.dmsd.thread;

 

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Semaphore;

 

public class SemaphoreTest {

         public static void main(String[] args) {

                   ExecutorService service = Executors.newCachedThreadPool();//定义一个线程池

                   final  Semaphore sp = new Semaphore(3);

                   for(int i=0;i<10;i++){

                            Runnable runnable = new Runnable(){

                                               public void run(){

                                               try {

                                                        sp.acquire();

                                               } catch (InterruptedException e1) {

                                                        e1.printStackTrace();

                                               }

                                               System.out.println("线程" + Thread.currentThread().getName() +

                                                                 "进入,当前已有" + (3-sp.availablePermits()) + "个并发");

                                               try {

                                                        Thread.sleep((long)(Math.random()*10000));

                                               } catch (InterruptedException e) {

                                                        e.printStackTrace();

                                               }

                                               System.out.println("线程" + Thread.currentThread().getName() +

                                                                 "即将离开");                                       

                                               sp.release();

                                               //下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元

                                               System.out.println("线程" + Thread.currentThread().getName() +

                                                                 "已离开,当前已有" + (3-sp.availablePermits()) + "个并发");                                              

                                     }

                            };

                            service.execute(runnable);                       

                   }

         }

 

}

运行结果:

线程pool-1-thread-3进入,当前已有2个并发

线程pool-1-thread-4进入,当前已有3个并发

线程pool-1-thread-1进入,当前已有2个并发

线程pool-1-thread-4即将离开

线程pool-1-thread-4已离开,当前已有2个并发

线程pool-1-thread-5进入,当前已有3个并发

线程pool-1-thread-3即将离开

线程pool-1-thread-3已离开,当前已有2个并发

线程pool-1-thread-2进入,当前已有3个并发

 

 

Semaphore可以维护当前访问自身的线程个数,并提供了同步机制,使用Semaphore可以控制同时访问资源的线程个数。

 

同步计数器(CountDownLatch):

应用场景:运动场上,裁判一下口令,所有运动员开始奔跑,每个运动员跑到终点都会给裁判返回一个结果,只要所有的运动员都到场终点以后裁判才会公布比赛结果。

示例代码:

package com.dmsd.thread;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.CyclicBarrier;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

 

public class CountdownLatchTest {

 

         public static void main(String[] args) {

                   ExecutorService service = Executors.newCachedThreadPool();

                   final CountDownLatch cdOrder = new CountDownLatch(1);

                   final CountDownLatch cdAnswer = new CountDownLatch(3);                

                   for(int i=0;i<3;i++){

                            Runnable runnable = new Runnable(){

                                               public void run(){

                                               try {

                                                        System.out.println("线程" + Thread.currentThread().getName() +

                                                                           "正准备接受命令");                                                     

                                                        cdOrder.await();

                                                        System.out.println("线程" + Thread.currentThread().getName() +

                                                        "已接受命令");                                                                        

                                                        Thread.sleep((long)(Math.random()*10000));       

                                                        System.out.println("线程" + Thread.currentThread().getName() +

                                                                           "回应命令处理结果");                                                

                                                        cdAnswer.countDown();                                               

                                               } catch (Exception e) {

                                                        e.printStackTrace();

                                               }                                   

                                     }

                            };

                            service.execute(runnable);

                   }                

                   try {

                            Thread.sleep((long)(Math.random()*10000));

                  

                            System.out.println("线程" + Thread.currentThread().getName() +

                                               "即将发布命令");                                                

                            cdOrder.countDown();

                            System.out.println("线程" + Thread.currentThread().getName() +

                            "已发送命令,正在等待结果");  

                            cdAnswer.await();

                            System.out.println("线程" + Thread.currentThread().getName() +

                            "已收到所有响应结果");      

                   } catch (Exception e) {

                            e.printStackTrace();

                   }                                   

                   service.shutdown();

 

         }

}

运行结果:

Thread-0 be ready to read data!

Thread-0have read data :null

Thread-1 be ready to write data!

Thread-1 have write data: 4394

Thread-3 be ready to write data!

Thread-3 have write data: 6867

Thread-4 be ready to read data!

Thread-2 be ready to read data!

Thread-4have read data :6867

Thread-2have read data :6867

Thread-5 be ready to write data!

Thread-5 have write data: 7615

Thread-0 be ready to read data!

Thread-0have read data :7615

Thread-1 be ready to write data!

Thread-1 have write data: 6050

Thread-3 be ready to write data!

Thread-3 have write data: 3908

Thread-4 be ready to read data!

Thread-2 be ready to read data!

 

 

该同步工具可以根据多个计数器组合,既可以控制线程的开始,也可以控制现场的结束。

 

障碍器(CyclicBarrier):

应用场景:一个旅游团到达旅游地之后,导游说每个人可以自由参观,等到下午三点的时候大家聚集到一起然后一起返回。

示例代码:

package com.dmsd.thread;

import java.util.concurrent.CyclicBarrier;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

 

public class CyclicBarrierTest {

 

         public static void main(String[] args) {

                   ExecutorService service = Executors.newCachedThreadPool();

                   final  CyclicBarrier cb = new CyclicBarrier(3);

                   for(int i=0;i<3;i++){

                            Runnable runnable = new Runnable(){

                                               public void run(){

                                               try {

                                                        Thread.sleep((long)(Math.random()*10000));       

                                                        System.out.println("线程" + Thread.currentThread().getName() +

                                                                           "即将到达集合地点1,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));                                                     

                                                        cb.await();

                                                       

                                                        Thread.sleep((long)(Math.random()*10000));       

                                                        System.out.println("线程" + Thread.currentThread().getName() +

                                                                           "即将到达集合地点2,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));

                                                        cb.await();       

                                                        Thread.sleep((long)(Math.random()*10000));       

                                                        System.out.println("线程" + Thread.currentThread().getName() +

                                                                           "即将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候"));                                                

                                                        cb.await();                                                     

                                               } catch (Exception e) {

                                                        e.printStackTrace();

                                               }                                   

                                     }

                            };

                            service.execute(runnable);

                   }

                   service.shutdown();

         }

}

 

线程间数据交换(Exchanger)

应用场景:

敌对的双方互相交换人质,只有双方都准备好之后同时进行交换。

示例代码:

package com.dmsd.thread;

import java.util.concurrent.Exchanger;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

 

public class ExchangerTest {

 

         public static void main(String[] args) {

                   ExecutorService service = Executors.newCachedThreadPool();

                   final Exchanger exchanger = new Exchanger();

                   service.execute(new Runnable(){

                            public void run() {

                                     try {                             

 

                                               String data1 = "zxx";

                                               System.out.println("线程" + Thread.currentThread().getName() +

                                               "正在把数据" + data1 +"换出去");

                                               Thread.sleep((long)(Math.random()*10000));

                                               String data2 = (String)exchanger.exchange(data1);

                                               System.out.println("线程" + Thread.currentThread().getName() +

                                               "换回的数据为" + data2);

                                     }catch(Exception e){

                                              

                                     }

                            }       

                   });

                   service.execute(new Runnable(){

                            public void run() {

                                     try {                             

 

                                               String data1 = "lhm";

                                               System.out.println("线程" + Thread.currentThread().getName() +

                                               "正在把数据" + data1 +"换出去");

                                               Thread.sleep((long)(Math.random()*10000));                                             

                                               String data2 = (String)exchanger.exchange(data1);

                                               System.out.println("线程" + Thread.currentThread().getName() +

                                               "换回的数据为" + data2);

                                     }catch(Exception e){

                                              

                                     }                                   

                            }       

                   });              

         }

}

运行结果:

线程pool-1-thread-1正在把数据zxx换出去

线程pool-1-thread-2正在把数据lhm换出去

线程pool-1-thread-1换回的数据为lhm

线程pool-1-thread-2换回的数据为zxx

 

  四种同步工具各有各的应用场景,根据自己的具体需求,我们可以综合使用这几种同步工具来更好的实现我们的业务。

 

 

你可能感兴趣的:(java)