JUC部分并发类使用方式
2022-05-18 19:51
441 查看
下面介绍的是JUC包下一些线程安全类的一些简单使用和一些小demo。
Semaphore
信号量,即可以同时使用的线程数,tryrequire就是将信号量减一,release就是信号量+1,当等于0就会阻塞,大于零才会唤醒。
当需要控制线程访问数量,可以使用信号量来做控制,比较简单。
下面是使用信号量改进的数据库连接池
@Slf4j public class SemaphoreConnection { // 连接池对象数组 private Connection[] connections; // 使用标记 private AtomicIntegerArray flagArrays; // 线程池大小 private Integer poolSize; /** * 信号量 */ Semaphore semaphore; public SemaphoreConnection(){ this.poolSize = 5; connections = new MarkConnection[5]; flagArrays = new AtomicIntegerArray(5); for (int i = 0; i < connections.length; i++) { connections[i] = new MarkConnection("连接" + i+1); } semaphore = new Semaphore(5); } // 连接池的初始化 public SemaphoreConnection(int poolSize) { this.poolSize = poolSize; connections = new MarkConnection[poolSize]; flagArrays = new AtomicIntegerArray(poolSize); for (int i = 0; i < connections.length; i++) { connections[i] = new MarkConnection("连接" + i); } semaphore = new Semaphore(poolSize); } // 向连接池中请求连接 public Connection getConnection(){ try { semaphore.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } while (true){ for (int i = 0; i < poolSize; i++) { // 进行cas请求,如果请求失败就失败 if (flagArrays.compareAndSet(i,0,1)){ return connections[i]; } } } } /** * 释放连接 * @param con */ public void releaseConnection(Connection con){ for (int i = 0; i < poolSize; i++) { if (con == connections[i]){ // 将连接标识置为0即空间连接 flagArrays.set(i,0); semaphore.release(); } } } public static void main(String[] args) { SemaphoreConnection myConnectionPoll = new SemaphoreConnection(3); for (int i = 0; i < 10; i++) { new Thread(() ->{ MarkConnection connection =(MarkConnection) myConnectionPoll.getConnection(); log.debug("获得锁{}",connection.getConName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } myConnectionPoll.releaseConnection(connection); log.debug("释放锁{}",connection.getConName()); }).start(); } } }
CountDownLatch
就是一个用来计数的,来解决线程之间通信的问题。
比如我需要两个线程执行完毕后再去执行主线程,我们可以用join方法,但是我们同样可以使用这个类来控制。
通过一个count,当其被减为0时,调用await阻塞的线程就会唤醒。
// 一个简单的demo @Slf4j public class Test2 { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(2); // for(int i = 0;i < 3;i++){ new Thread(()->{ log.debug("来啦"); try { Thread.sleep(1000); countDownLatch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } log.debug("干啦兄弟们"); }).start(); new Thread(()->{ log.debug("来啦"); try { Thread.sleep(2000); countDownLatch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } log.debug("干啦兄弟们"); }).start(); // } countDownLatch.await(); log.debug("开吃了兄弟们"); } }
同时可以作为微服务下的多线程调用,当我们需要多个微服务的结果时,我们可以使用多线程,调用多线程池使用多线程的方法远程调用,可以使用该类控制主线程等待线程池中的线程执行完后执行主线程。但是使用Future可以解决问题,所以还是建议使用future,使用callable方法。
CyclicBarrier
作为一个和CountDownLatch功能相似,但是它却是可以循环使用的,当其置为0时,唤醒线程后,就会恢复到初始值。可以继续使用,而CountDownLatch却是一次性的,需要重复创建线程。
CyclicBarrier主要是调用一个await方法,等待其他线程,当到达数量的线程完成后,就会唤醒被await方法阻塞的线程。
// demo @Slf4j public class Test3 { public static void main(String[] args) { CyclicBarrier cyclicBarrier = new CyclicBarrier(3); new Thread(()->{ log.debug("来啦"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } log.debug("干啦兄弟们"); try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }).start(); new Thread(()->{ log.debug("来啦"); try { Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); } log.debug("干啦兄弟们"); try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }).start(); try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } log.debug("来了啊"); } }
ConcurrentHashMap
保证了多线程下hashmap的安全。
jdk1.7时会产生死链,因为jdk1.7时多线程下是在链表头往里面加,而 不是1.8在链表尾加,所以会出现多线程下链表出现环,无法结束程序。
Concurrent类在多线程下的表现为
- 内部使用cas进行优化,可以支持较大的吞吐量
- 弱一致性 迭代时的弱一致性,当在迭代是被更新,迭代不会报错但是会表现出旧值
- size的弱一致性,会读到旧值
- 读取一致性
fast-fail快速失败就是当其他线程修改了,非安全容器就会让正在遍历的直接抛出异常。
相关文章推荐
- osgi使用 equnix框架 Bridge方式搭建方法(部分来源于ibm网站)
- 如何在 XCode 4.2 設定部分程式碼不使用 ARC 方式分享(转)
- 如何在 XCode 4.2 設定部分程式碼不使用 ARC 方式分享(转)
- awk的使用 第二部分 awk的运行方式
- 部分告别Qt调试,另类使用显示Qt程序中函数加载顺序的方式
- 使用js和css方式,让IE8,IE9支持部分css3,html5
- 如何在 XCode 4.2 設定部分程式碼不使用 ARC 方式分享(转)
- 微信支付-扫码支付方式在ThinkPHP商城中的使用(第三部分)
- SpringMVC和FreeMarker整合中使用注解方式的后台数据校验validate(部分自己扩展)
- git部分命令的使用方式
- sql server中order by部分使用方式
- 类文件方式使用 FlashRemoting+.NET(.net部分更换成开源控件)
- order by部分使用方式
- 微信支付-扫码支付方式在ThinkPHP商城中的使用(第二部分)
- 当前使用的IP地址有4个字节(32)组成,即IPV4编码方式。每个IP地址包换两部分:网络号和主机号。当分配给主机号的二进制位越多,则能标识的主机数就越多,相应地能标识的网络数就越少,反之亦然。
- springboot+redis(注解方式)使用(java代码部分)
- QAndroidJniObject类 部分函数使用方式
- 对页面中的某一个变量或部分代码段使用不同的的编码方式
- Web-HTTP协议5题记录,请求方式、302跳转、cookie、基础认证、响应包源代码-burpsuite部分功能的使用
- jdk1.8的部分使用方式