为了账号安全,请及时绑定邮箱和手机立即绑定

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

标签:
Java

您好,我是湘王,这是我的慕课手记,欢迎您来,欢迎您再来~


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

1、同步器;

2、线程安全的容器;

3、阻塞队列;

4、一些特殊的类。

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

https://img1.sycdn.imooc.com//635fd5ae0001d37a14280769.jpg


 

下面从同步器开始

常用的JUC同步器有四个

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

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

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

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

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

 

CountDownLatch

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

https://img1.sycdn.imooc.com//635fd5b50001e82c05960543.jpg

 

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的效果是

https://img1.sycdn.imooc.com//635fd5be0001ac1f06600566.jpg


 

Semaphore

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

https://img1.sycdn.imooc.com//635fd5c40001ce6f09530781.jpg

 

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执行后的效果是

https://img1.sycdn.imooc.com//635fd5ca0001c25d06590414.jpg


 

CyclicBarrier

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

https://img1.sycdn.imooc.com//635fd5d20001c24e04780448.jpg



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执行后的效果是

https://img1.sycdn.imooc.com//635fd5d90001e2ae06590730.jpg



Exchanger

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

https://img1.sycdn.imooc.com//635fd5de000187e606940154.jpg

 

 

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执行后的效果是

https://img1.sycdn.imooc.com//635fd5e20001582b06600147.jpg

 

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




 

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





点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消