Java多线程(7):JUC(上)

打印 上一主题 下一主题

主题 679|帖子 679|积分 2037

您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~
 
前面把线程相关的生命周期、关键字、线程池(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实例代码:
  1. /**
  2. * 发令枪
  3. *
  4. * @author 湘王
  5. */
  6. public class CountDownLatchTester implements Runnable {
  7.     static final CountDownLatch latch = new CountDownLatch(10);
  8.     @Override
  9.     public void run() {
  10.         // 检查任务
  11.         try {
  12.             System.out.println(Thread.currentThread().getName() + " 检查完毕!");
  13.         } catch (Exception e) {
  14.             e.printStackTrace();
  15.         } finally {
  16.             latch.countDown();
  17.         }
  18.     }
  19.     public static void main(String[] args) throws InterruptedException {
  20.         ExecutorService executor = Executors.newFixedThreadPool(5);
  21.         for (int i = 10; i > 0; i--) {
  22.             Thread.sleep(1000);
  23.             executor.submit(new CountDownLatchTester());
  24.             System.out.println(i);
  25.         }
  26.         Thread.sleep(1000);
  27.         // 检查
  28.         latch.await();
  29.         System.out.println();
  30.         System.out.println("点火,发射!");
  31.         // 关闭线程池
  32.         executor.shutdown();
  33.     }
  34. }
复制代码
 
 
执行CountDownLatch的效果是:

 
 
 
 
二、Semaphore
Semaphore的功能如果用图来表示的话,就会是这样的:
 
 
 
 
 
Semaphore实例代码:
 
  1. /**
  2. * 信号量(摇号器)
  3. *
  4. * @author 湘王
  5. */
  6. public class SemaphoreTester implements Runnable {
  7.     static final Semaphore semaphore = new Semaphore(3);
  8.     @Override
  9.     public void run() {
  10.         try {
  11.             semaphore.acquire();
  12.             System.out.println(Thread.currentThread().getName() + " 开始进餐");
  13.             Thread.sleep(1000);
  14.         } catch (Exception e) {
  15.             e.printStackTrace();
  16.         }
  17.         semaphore.release();
  18.     }
  19.     public static void main(String[] args) {
  20.         ExecutorService excutor = Executors.newFixedThreadPool(15);
  21.         for (int i = 0; i < 15; i++) {
  22.             excutor.submit(new SemaphoreTester());
  23.         }
  24.         excutor.shutdown();
  25.     }
  26. }
复制代码
 
 
Semaphore执行后的效果是:
 
 
 
 
 
三、CyclicBarrier
CyclicBarrier的功能如果用图来表示的话,就会是这样的:
 
 
 
 
 
CyclicBarrier实例代码:
  1. /**
  2. * 栅栏
  3. *
  4. * @author 湘王
  5. */
  6. public class CyclicBarrierTester implements Runnable {
  7.     private final static CyclicBarrier barrier = new CyclicBarrier(3);
  8.     @Override
  9.     public void run() {
  10.         try {
  11.             Thread.sleep(1000);
  12.             System.out.println(Thread.currentThread().getName() + " 已达到预定位置,等待指令...");
  13.             // 只有最后一个线程执行后,所有的线程才能执行2
  14.             barrier.await();
  15.             Thread.sleep(1000);
  16.             // 2 所有线程都会执行的动作
  17.             System.out.println(Thread.currentThread().getName() + " 已突破第一道封锁线");
  18.         } catch (Exception e) {
  19.             e.printStackTrace();
  20.         }
  21.     }
  22.     public static void main(String[] args) {
  23.         ExecutorService executor = Executors.newFixedThreadPool(3);
  24.         for (int i = 0; i < 15; i++) {
  25.             executor.submit(new CyclicBarrierTester());
  26.         }
  27.         // 关闭线程池
  28.         executor.shutdown();
  29.     }
  30. }
复制代码
 
 
CyclicBarrier执行后的效果是:

 
 
 
四、Exchanger
Exchanger的功能如果用图来表示的话,就会是这样的:
 
 
 
 
 
Exchanger实例代码:
 
  1. /**
  2. * 交换机
  3. *
  4. * @author 湘王
  5. */
  6. public class ExchangerTester implements Runnable {
  7.     Exchanger<Object> exchanger = null;
  8.     Object object = null;
  9.     public ExchangerTester(Exchanger<Object> exchanger, Object object) {
  10.         this.exchanger = exchanger;
  11.         this.object = object;
  12.     }
  13.     @Override
  14.     public void run() {
  15.         try {
  16.             Object previous = this.object;
  17.             this.object = this.exchanger.exchange(this.object);
  18.             System.out.println(Thread.currentThread().getName() + " 用对象 " + previous + " 换对象 " + this.object);
  19.         } catch (InterruptedException e) {
  20.             e.printStackTrace();
  21.         }
  22.     }
  23.     public static void main(String[] args) {
  24.         Exchanger<Object> exchanger = new Exchanger<Object>();
  25.         ExchangerTester tester1 = new ExchangerTester(exchanger, "A");
  26.         ExchangerTester tester2 = new ExchangerTester(exchanger, "B");
  27.         new Thread(tester1).start();
  28.         new Thread(tester2).start();
  29.     }
  30. }
复制代码
 
 
Exchanger执行后的效果是:
 
 
 
 
把这四种同步器掌握好(包括它们的组合使用),几乎可以解决90%以上的使用多线程的场景问题,再也不用担心不会多线程了。
 
 
 
 
感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

慢吞云雾缓吐愁

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表