湘潭网站建设 x磐石网络,西安网页设计多少钱,网站建设中网站需求分析报告内容,安阳县县长CountDownLatch
①. CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞
②. 其它线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞)
③. 计数器的值变为0时,因await方法阻塞的线程会被唤醒,继续执行
public static void m…CountDownLatch
①. CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞
②. 其它线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞)
③. 计数器的值变为0时,因await方法阻塞的线程会被唤醒,继续执行
public static void main(String[] args) throws Exception {CountDownLatch countDownLatch new CountDownLatch(6);for (int i 1; i 6; i) {new Thread(() - {System.out.println(Thread.currentThread().getName() \t);countDownLatch.countDown();}, i ).start();}countDownLatch.await();System.out.println(Thread.currentThread().getName() \t班长关门走人,main线程是班长);}比如说CountDownLatch你就可以回答前面提到了CountDownLatch也是基于AQS实现的它的实现机制很简单
当我们在构建CountDownLatch对象时传入的值其实就会赋值给 AQS 的关键变量state执行CountDownLatch的countDown方法时其实就是利用CAS 将state 减一执行await方法时其实就是判断state是否为0不为0则加入到阻塞队列中将该线程阻塞掉除了头结点因为头节点会一直自旋等待state为0当state为0时头节点把剩余的在队列中阻塞的节点也一并唤醒。
再简单总结下CountDownlatch基于AQS实现会将构造CountDownLatch的入参传递至statecountDown()就是在利用CAS将state减-1 await()实际就是让头节点一直在等待state为0时释放所有等待的线程
CyclicBarrier
CyclicBarrier原理
1、它没有像CountDownLatch和ReentrantLock使用AQS的state变量而是使用CyclicBarrier内部维护的内部维护count变量
2、同时CyclicBarrier借助ReentrantLock加上Condition实现等待唤醒的功能
parties变量和condition队列
在构建CyclicBarrier时传入的值是parties变量同时也会赋值给CyclicBarrier内部维护count变量这是可以复用的关键
//parties表示屏障拦截的线程数量当屏障撤销时先执行barrierAction然后在释放所有线程
public CyclicBarrier(int parties, Runnable barrierAction)
//barrierAction默认为null
public CyclicBarrier(int parties)每次调用await时会将count -1 操作count值是直接使用ReentrantLock来保证线程安全性
如果count不为0则添加则condition队列中
如果count等于0时则把节点从condition队列添加至AQS的队列中进行全部唤醒并且将parties的值重新赋值为count的值实现复用
再简单总结下CyclicBarrier则利用ReentrantLock和Condition自身维护了count和parties变量。 每次调用await将count-1并将线程加入到condition队列上。等到count为0时则将condition队列的节点移交至AQS队列并全部释放。
阻塞任务线程而非主线程 CountDownLatch和CyclicBarrier都是线程同步的工具类。可以发现这两者的等待主体是不一样的。
CountDownLatch调用await()通常是主线程/调用线程CyclicBarrier调用await()是在任务线程调用的所以CyclicBarrier中的阻塞的是任务的线程而主线程是不受影响的。
比如集齐7颗龙珠就能召唤神龙。 //集齐7颗龙珠就能召唤神龙
public class CyclicBarrierDemo {public static void main(String[] args) {// public CyclicBarrier(int parties, Runnable barrierAction) {}CyclicBarrier cyclicBarriernew CyclicBarrier(7,()-{System.out.println(召唤龙珠);});for (int i 1; i 7; i) {final int tempi;new Thread(()-{System.out.println(Thread.currentThread().getName()\t收集到了第temp颗龙珠);try {cyclicBarrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}).start();}}
}共同抵达时的执行操作
屏障的抵达操作每个线程执行时都会碰到一个屏障直到所有线程执行结束然后屏障便会打开使所有线程继续往下执行。
CyclicBarrier支持一个可选的Runnable barrierAction命令在一组线程中的最后一个线程到达之后但在释放所有线程之前运行一次。若在继续所有参与线程之前更新共享状态此屏障操作很有用。
如果一个寝室四个人约好了去球场打球由于四个人准备工作不同所以约好在楼下集合并且四个人集合好之后一起出发去球场。
private static final ThreadPoolExecutor threadPool new ThreadPoolExecutor(4, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueueRunnable());//当拦截线程数达到4时便优先执行barrierAction然后再执行被拦截的线程。private static final CyclicBarrier cb new CyclicBarrier(4, () - System.out.println(寝室四兄弟一起出发去球场));private static class MyThread extends Thread {private String name;public MyThread(String name) {this.name name;}Overridepublic void run() {System.out.println(name 开始从宿舍出发);try {cb.await();//线程的具体业务操作TimeUnit.SECONDS.sleep(1);System.out.println(name 从楼底下出发);TimeUnit.SECONDS.sleep(1);System.out.println(name 到达操场);} catch (Exception e) {e.printStackTrace();}}}public static void main(String[] args) {String[] str {李明, 王强, 刘凯, 赵杰};for (int i 0; i 4; i) {threadPool.execute(new MyThread(str[i]));}try {Thread.sleep(4000);System.out.println(四个人一起到达球场现在开始打球);} catch (InterruptedException e) {e.printStackTrace();}}屏障复用
CyclicBarrier是可循环利用的屏障顾名思义这个名字也将这个类的特点给明确地表示出来了。可重复利用说明该类创建的对象可以复用CyclicBarrier是一个同步工具类它允许一组线程互相等待直到到达某个公共屏障点。与CountDownLatch不同的是该barrier在释放等待线程后可以重用所以称它为循环Cyclic的屏障Barrier。
现在对CyclicBarrier进行复用…又来了一拨人看看愿不愿意一起打 private static final ThreadPoolExecutor threadPool new ThreadPoolExecutor(4, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueueRunnable());//当拦截线程数达到4时便优先执行barrierAction然后再执行被拦截的线程。private static final CyclicBarrier cb new CyclicBarrier(4, () - System.out.println(寝室四兄弟一起出发去球场));private static class MyThread extends Thread {private String name;public MyThread(String name) {this.name name;}Overridepublic void run() {System.out.println(name 开始从宿舍出发);try {cb.await();TimeUnit.SECONDS.sleep(1);System.out.println(name 从楼底下出发);TimeUnit.SECONDS.sleep(1);System.out.println(name 到达操场);} catch (Exception e) {e.printStackTrace();}}}public static void main(String[] args) {String[] str {李明, 王强, 刘凯, 赵杰};for (int i 0; i 4; i) {threadPool.execute(new MyThread(str[i]));}try {Thread.sleep(4000);System.out.println(四个人一起到达球场现在开始打球);System.out.println();System.out.println(现在对CyclicBarrier进行复用.....);System.out.println(又来了一拨人看看愿不愿意一起打);} catch (InterruptedException e) {e.printStackTrace();}String[] str1 {王二,洪光,雷兵,赵三};for (int i 0; i 4; i) {threadPool.execute(new MyThread(str1[i]));}try {Thread.sleep(4000);System.out.println(四个人一起到达球场表示愿意一起打球现在八个人开始打球);} catch (InterruptedException e) {e.printStackTrace();}}
Semaphore
Semaphore 是什么Semaphore 通常我们叫它信号量 可以用来控制同时访问特定资源的线程数量通过协调各个线程以保证合理的使用资源。
使用场景
通常用于那些资源有明确访问数量限制的场景常用于限流 。
比如数据库连接池同时进行连接的线程有数量限制连接不能超过一定的数量当连接达到了限制数量后后面的线程只能排队等前面的线程释放了数据库连接才能获得数据库连接。比如停车场场景车位数量有限同时只能容纳多少台车车位满了之后只有等里面的车离开停车场外面的车才可以进入。可以把它简单的理解成我们停车场入口立着的那个显示屏每有一辆车进入停车场显示屏就会显示剩余车位减1每有一辆车从停车场出去显示屏上显示的剩余车辆就会加1当显示屏上的剩余车位为0时停车场入口的栏杆就不会再打开车辆就无法进入停车场了直到有一辆车从停车场出去为止。比如,接口限流 ,应用限流 ,商品限流…
Semaphore常用方法说明
acquire()
获取一个令牌在获取到令牌、或者被其他线程调用中断之前线程一直处于阻塞状态。tryAcquire(long timeout, TimeUnit unit)
尝试在指定时间内获得令牌,返回获取令牌成功或失败不阻塞线程。release()
释放一个令牌唤醒一个获取令牌不成功的阻塞线程。hasQueuedThreads()
等待队列里是否还存在等待线程。getQueueLength()
获取等待队列里阻塞的线程数。drainPermits()
清空令牌把可用令牌数置为0返回清空令牌的数量。availablePermits()
返回可用的令牌数量。用semaphore 实现停车场提示牌功能
每个停车场入口都有一个提示牌上面显示着停车场的剩余车位还有多少当剩余车位为0时不允许车辆进入停车场直到停车场里面有车离开停车场这时提示牌上会显示新的剩余车位数。
业务场景
停车场容纳总停车量10。当一辆车进入停车场后显示牌的剩余车位数响应的减1.每有一辆车驶出停车场后显示牌的剩余车位数响应的加1。停车场剩余车位不足时车辆只能在外面等待。
public class TestCar {//停车场同时容纳的车辆10private static Semaphore semaphorenew Semaphore(10);public static void main(String[] args) {//模拟100辆车进入停车场for(int i0;i100;i){Thread threadnew Thread(new Runnable() {public void run() {try {System.out.println(Thread.currentThread().getName()来到停车场);if(semaphore.availablePermits()0){System.out.println(车位不足请耐心等待);}semaphore.acquire();//获取令牌尝试进入停车场System.out.println(Thread.currentThread().getName()成功进入停车场);Thread.sleep(new Random().nextInt(10000));//模拟车辆在停车场停留的时间System.out.println(Thread.currentThread().getName()驶出停车场);semaphore.release();//释放令牌腾出停车场车位} catch (InterruptedException e) {e.printStackTrace();}}},i号车);thread.start();}}
}用semaphore 实现防止商品超卖
package com.limiting.semaphore;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;/*** 秒杀防止商品超卖现象*/
public class SemaphoreCommodity {//商品池private MapString, Semaphore mapnew ConcurrentHashMap();//初始化商品池public SemaphoreCommodity() {//手机10部map.put(phone,new Semaphore(10));//电脑4台map.put(computer,new Semaphore(4));}/**** param name 商品名称* return 购买是否成功*/public boolean getbuy(String name) throws Exception {Semaphore semaphore map.get(name);while (true) {int availablePermit semaphore.availablePermits();if (availablePermit0) {//商品售空return false;}boolean b semaphore.tryAcquire(1, TimeUnit.SECONDS);if (b) {System.out.println(抢到商品了);///处理逻辑return true;}}}public static void main(String[] args) throws Exception {SemaphoreCommodity semaphoreCommoditynew SemaphoreCommodity();for (int i 0; i 10; i) {new Thread(()-{try {System.out.println(semaphoreCommodity.getbuy(computer));} catch (Exception e) {e.printStackTrace();}}).start();}}
}用semaphore 实现接口限流
切面注解SemaphoreDoc
package com.limiting.semaphore;import java.lang.annotation.*;DocumentedTarget({ElementType.METHOD})//作用:方法
Retention(RetentionPolicy.RUNTIME)
public interface SemaphoreDoc {String key(); //建议设置不然可能发生,不同方法重复限流现象int limit() default 3;int blockingTime() default 3;}切面类SemaphoreAop
Component
Aspect
public class SemaphoreAop {//这里需要注意了这个是将自己自定义注解作为切点的根据路径一定要写正确了Pointcut(value annotation(com.limiting.semaphore.SemaphoreDoc))public void semaphoreDoc() {}//限流池private static MapString, Semaphore mapnew ConcurrentHashMap();Around(semaphoreDoc())public Object around(ProceedingJoinPoint joinPoint) throws Throwable {Object res null;MethodSignature signature (MethodSignature)joinPoint.getSignature();SemaphoreDoc annotation signature.getMethod().getAnnotation(SemaphoreDoc.class);int blockingTime annotation.blockingTime();int limit annotation.limit();String key annotation.key();StringBuilder name new StringBuilder(keysignature.getMethod().getName());//方法名for (String parameterName : signature.getParameterNames()) {name.append(parameterName);}Semaphore semaphore map.get(name.toString());if (semaphore null) {Semaphore semaphore1 new Semaphore(limit);map.put(name.toString(),semaphore1);semaphoresemaphore1;}try {//获取令牌boolean b semaphore.tryAcquire(blockingTime, TimeUnit.SECONDS);if (b) {//如果拿到令牌了那么执行方法try {res joinPoint.proceed();} catch (Throwable e) {e.printStackTrace();}} else {//在一定时间内拿不到令牌那么就访问失败throw new Exception(访问超时,目前请求人数过多请稍后在试);}} finally {//释放令牌腾出位置semaphore.release();}return res;}}