Java多线程(7):JUC(上)
  3EPyMqobg2PT 2023年11月01日 74 0

您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~

 

前面把线程相关的生命周期、关键字、线程池(ThreadPool)、ThreadLocal、CAS、锁和AQS都讲完了,现在就剩下怎么来用多线程了。而要想用好多线程,其实是可以取一些巧的,比如JUC(好多面试官喜欢问的JUC,就是现在要讲的JUC)。JUC就是java.util.concurrent的首字母缩写,它是Java并发工具包就是中提供的各种工具类的统称,主要分为几大类:

1、同步器;

2、线程安全的容器;

3、阻塞队列;

4、一些特殊的类。

他们都有各自适合应用场景。这里是并发工具包相关类的继承结构:

 

 

 

 

 

下面从同步器开始。

常用的JUC同步器有四个:

1、CountDownLatch:字面意思是倒计时锁,如果有“倒计时”的需求,那么CountDownLatch是最好的工具。它还有一个别称:发令枪。可以想象一下,火箭点火发射的时候,所有设备、部门都会依次检查确认,如果全部都确认准备好了才能开始发射,也就是等倒数到指定的数字(一般是0)的时候,就开始执行预设动作;

2、Semaphore:字面意思信号量,好比红绿灯,或者就餐排队时餐馆发的数字序号,一次只允许若干个线程执行。这个在昨天的例子里面也已经演示过了,而且还是通过自定义AQS来实现的(信号量可能不太好理解,我更倾向于叫它摇号器);

3、CyclicBarrier:字面意思是屏障或者栅栏,与CountDownLatch比较像,但它侧重于工作本身,即指定的若干个工作都满足考核标准(某个屏障)之后,才能继续进行下面的工作,且可反复使用;

4、Exchanger:用于线程之间交换数据,更形象地说法是“交换机”,即当一个线程完成某项工作后想与另一个线程交换数据,就可以使用这个工具类。

下面来一个个地演示它们的用法。

 

一、CountDownLatch

CountDownLatch的功能如果用图来表示的话,就会是这样的:

 

 

 

 

CountDownLatch实例代码:

/** * 发令枪 * * @author 湘王 */
public class CountDownLatchTester implements Runnable { static final CountDownLatch latch = new CountDownLatch(10); @Override public void run() { // 检查任务
        try { System.out.println(Thread.currentThread().getName() + " 检查完毕!"); } catch (Exception e) { e.printStackTrace(); } finally { latch.countDown(); } } public static void main(String[] args) throws InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(5); for (int i = 10; i > 0; i--) { Thread.sleep(1000); executor.submit(new CountDownLatchTester()); System.out.println(i); } Thread.sleep(1000); // 检查
 latch.await(); System.out.println(); System.out.println("点火,发射!"); // 关闭线程池
 executor.shutdown(); } }

 

 

执行CountDownLatch的效果是:

 

 

 

 

Semaphore

Semaphore的功能如果用图来表示的话,就会是这样的:

 

 

 

 

 

Semaphore实例代码:

 

/** * 信号量(摇号器) * * @author 湘王 */
public class SemaphoreTester implements Runnable { static final Semaphore semaphore = new Semaphore(3); @Override public void run() { try { semaphore.acquire(); System.out.println(Thread.currentThread().getName() + " 开始进餐"); Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } semaphore.release(); } public static void main(String[] args) { ExecutorService excutor = Executors.newFixedThreadPool(15); for (int i = 0; i < 15; i++) { excutor.submit(new SemaphoreTester()); } excutor.shutdown(); } }

 

 

Semaphore执行后的效果是:

 

 

 

 

 

CyclicBarrier

CyclicBarrier的功能如果用图来表示的话,就会是这样的:

 

 

 

 

 

CyclicBarrier实例代码:

/** * 栅栏 * * @author 湘王 */
public class CyclicBarrierTester implements Runnable { private final static CyclicBarrier barrier = new CyclicBarrier(3); @Override public void run() { try { Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + " 已达到预定位置,等待指令..."); // 只有最后一个线程执行后,所有的线程才能执行2
 barrier.await(); Thread.sleep(1000); // 2 所有线程都会执行的动作
            System.out.println(Thread.currentThread().getName() + " 已突破第一道封锁线"); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(3); for (int i = 0; i < 15; i++) { executor.submit(new CyclicBarrierTester()); } // 关闭线程池
 executor.shutdown(); } }

 

 

CyclicBarrier执行后的效果是:

 

 

 

Exchanger

Exchanger的功能如果用图来表示的话,就会是这样的:

 

 

 

 

 

Exchanger实例代码:

 

/** * 交换机 * * @author 湘王 */
public class ExchangerTester implements Runnable { Exchanger<Object> exchanger = null; Object object = null; public ExchangerTester(Exchanger<Object> exchanger, Object object) { this.exchanger = exchanger; this.object = object; } @Override public void run() { try { Object previous = this.object; this.object = this.exchanger.exchange(this.object); System.out.println(Thread.currentThread().getName() + " 用对象 " + previous + " 换对象 " + this.object); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { Exchanger<Object> exchanger = new Exchanger<Object>(); ExchangerTester tester1 = new ExchangerTester(exchanger, "A"); ExchangerTester tester2 = new ExchangerTester(exchanger, "B"); new Thread(tester1).start(); new Thread(tester2).start(); } }

 

 

Exchanger执行后的效果是:

 

 

 

 

把这四种同步器掌握好(包括它们的组合使用),几乎可以解决90%以上的使用多线程的场景问题,再也不用担心不会多线程了。

 

 


 

 

感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~

 

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  2Vtxr3XfwhHq   2024年05月17日   53   0   0 Java
  Tnh5bgG19sRf   2024年05月20日   109   0   0 Java
  8s1LUHPryisj   2024年05月17日   46   0   0 Java
  aRSRdgycpgWt   2024年05月17日   47   0   0 Java
3EPyMqobg2PT