java.util.concurrent和工具类
三、Semaphor信号量
信号量可以干什么呢?根据一些阀值做访问控制。我们这里模拟一个当多个线程并发一段代码的时候,如何控制其访问速度
import java.util.Random; import java.util.concurrent.Semaphore;
public class SemaphoreTest { private final static Semaphore MAX_SEMA_PHORE = new Semaphore(10); public static void main(String []args) { for(int i = 0 ; i < 100 ; i++) { final int num = i; final Random radom = new Random(); new Thread() { public void run() { boolean acquired = false; try { MAX_SEMA_PHORE.acquire(); acquired = true; System.out.println("我是线程:" + num + " 我获得了使用权!" + DateTimeUtil.getDateTime()); long time = 1000 * Math.max(1, Math.abs(radom.nextInt() % 10)); Thread.sleep(time); System.out.println("我是线程:" + num + " 我执行完了!" + DateTimeUtil.getDateTime()); }catch(Exception e) { e.printStackTrace(); }finally { if(acquired) { MAX_SEMA_PHORE.release(); } } } }.start(); } } } |
上述是简单模拟并发100个线程去访问一段程序,此时要控制最多同时运行的是10个,用到了这个信号量,运行程序用了一个线程睡眠一个随机的时间来代替,你可以看到后面有线程说自己释放了,就有线程获得了,没释放是获取不到的
四、Exchanger线程交互
用于线程之间交互数据,且在并发时候使用,两两交换,交换中不会因为线程多而混乱,发送出去没接收到会一直等,由交互器完成交互过程
import java.util.concurrent.Exchanger;
public class ExchangerTest {
public static void main(String []args) { final Exchanger <Integer>exchanger = new Exchanger<Integer>(); for(int i = 0 ; i < 10 ; i++) { final Integer num = i; new Thread() { public void run() { System.out.println("我是线程:Thread_" + this.getName() + "我的数据是:" + num); try { Integer exchangeNum = exchanger.exchange(num); Thread.sleep(1000); System.out.println("我是线程:Thread_" + this.getName() + "我原先的数据为:" + num + " , 交换后的数据为:" + exchangeNum); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); } } } |
这里运行你可以看到,如果某个线程和另一个线程传送了数据,它接受到的数据必然是另一个线程传递给他的,中间步骤由Exchanger去控制
五、CyclicBarrier关卡模式
当你在很多环节需要卡住,要多个线程同时在这里都达到后,再向下走,很有用
假如,团队出去旅行,大家一起先达到酒店住宿,然后一起达到游乐的地方游玩,然后一起坐车回家,每次需要点名后确认相关人员均达到,然后LZ一声令下,触发,大伙就疯子般的出发了
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier;
public class BarrierTest {
private static final int THREAD_COUNT = 10;
private final static CyclicBarrier CYCLIC_BARRIER = new CyclicBarrier(THREAD_COUNT , new Runnable() { public void run() { System.out.println("======>我是导游,本次点名结束,准备走下一个环节!"); } } );
public static void main(String []args) throws InterruptedException, BrokenBarrierException { for(int i = 0 ; i < 10 ; i++) { new Thread(String.valueOf(i)) { public void run() { try { System.out.println("我是线程:" + this.getName() + " 我们达到旅游地点!"); CYCLIC_BARRIER.await(); System.out.println("我是线程:" + this.getName() + " 我开始骑车!"); CYCLIC_BARRIER.await(); System.out.println("我是线程:" + this.getName() + " 我们开始爬山!"); CYCLIC_BARRIER.await(); System.out.println("我是线程:" + this.getName() + " 我们回宾馆休息!"); CYCLIC_BARRIER.await(); System.out.println("我是线程:" + this.getName() + " 我们开始乘车回家!"); CYCLIC_BARRIER.await(); System.out.println("我是线程:" + this.getName() + " 我们到家了!"); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }.start(); } } } |
测试结果中可以发现,大家一起走到某个步骤后,导游说:“我是导游,本次点名结束,准备走下一个环节!”,然后才会进入下一个步骤,OK,这个有点意思吧,其实赛马也是这个道理,只是赛马通常只有一个步骤,所以我们还有一个方式是:
六、CountDownLatch计数器
CountDownLatch的方式来完成赛马操作,CountDownLatch是用计数器来做的,所以它不可以被复用,如果要多次使用,就要从新new一个出来才可以。我们下面的代码中,用两组赛马,每组5个参与者来,做一个简单测试
import java.util.concurrent.CountDownLatch;
public class CountDownLatchTest {
private final static int GROUP_SIZE = 5;
public static void main(String []args) { processOneGroup("分组1"); processOneGroup("分组2"); }
private static void processOneGroup(final String groupName) { final CountDownLatch start_count_down = new CountDownLatch(1); final CountDownLatch end_count_down = new CountDownLatch(GROUP_SIZE); System.out.println("==========================>\n分组:" + groupName + "比赛开始:"); for(int i = 0 ; i < GROUP_SIZE ; i++) { new Thread(String.valueOf(i)) { public void run() { System.out.println("我是线程组:【" + groupName + "】,第:" + this.getName() + " 号线程,我已经准备就绪!"); try { start_count_down.await();//等待开始指令发出即:start_count_down.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("我是线程组:【" + groupName + "】,第:" + this.getName() + " 号线程,我已执行完成!"); end_count_down.countDown(); } }.start(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("各就各位,预备!"); start_count_down.countDown();//开始赛跑 try { end_count_down.await();//等待多个赛跑者逐个结束 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("分组:" + groupName + "比赛结束!"); } } |
本教程由尚硅谷教育大数据研究院出品,如需转载请注明来源,欢迎大家关注尚硅谷公众号(atguigu)了解更多。