目录

8. Callable接口

8.1 创建线程的多种方式

8.2 概述

8.3 用Callable接口创建Thred线程

8.4 小结(重点)

9. JUC 三大辅助类

9.1 概述

9.2 减少计数 CountDownLatch

9.3 循环栅栏 CyclicBarrier

9.4 信号灯 Semaphore


8. Callable接口

8.1 创建线程的多种方式

  1. 继承Thread类
  2. 实现Runnable接口
  3. Callable接口
  4. 线程池

8.2 概述

目前我们学习了有两种创建线程的方法一种是通过创建 Thread 类,另一种是 通过使用 Runnable 创建线程。但是,Runnable 缺少的一项功能是,当线程 终止时(即 run()完成时),我们无法使线程返回结果。为了支持此功能, Java 中提供了 Callable 接口。

==现在我们学习的是创建线程的第三种方案---Callable 接口==

Callable 接口的特点如下(重点)

Runnable的 run()的方法没有返回值、不能产生异常

实现 Callable 而必须重写 call() 方法

  1. 有返回值:需要返回 call()方法的结果。
  2. 可以引发异常。

• 不能直接替换 runnable,因为 Thread 类的构造方法根本没有 Callable

// 创建新类 MyThread 实现 runnable 接口
class MyThread implements Runnable{@Overridepublic void run() {}
}
// 新类 MyThread2 实现 callable 接口
class MyThread2 implements Callable<Integer>{@Overridepublic Integer call() throws Exception {return 200;}}

• 不能直接替换 runnable,因为 Thread 类的构造方法根本没有 Callable

8.3 用Callable接口创建Thred线程

找一个类,既和Runnable有关系,又和Callable也有关系

  1. Runnbale接口有实现类:FutureTask
  2. FutureTask构造可以传递Callable

Runnable接口有实现类FutureTask(中间对象)

FutureTask的构造函数有Callable参数,通过FutureTask创建线程对象

public class CallableDemo {public static void main(String[] args) throws ExecutionException, InterruptedException{new Thread(()->{System.out.println(Thread.currentThread().getName()+"执行Runnable");}).start();FutureTask<String> task = new FutureTask<>(() -> {System.out.println(Thread.currentThread().getName() + "使用Callable接口");return "Callable接口的返回值";});new Thread(task).start();System.out.println("Callable返回值:" + task.get());}
}

8.4 小结(重点)

在主线程中需要执行比较耗时的操作时,但又不想阻塞主线程时,可以把这些 作业交给 Future 对象在后台完成, 当主线程将来需要时,就可以通过 Future 对象获得后台作业的计算结果或者执行状态

• 一般 FutureTask 多用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。

• 仅在计算完成时才能检索结果;如果计算尚未完成,则阻塞 get 方法。一旦计 算完成,就不能再重新开始或取消计算。get 方法而获取结果只有在计算完成 时获取,否则会一直阻塞直到任务转入完成状态,然后会返回结果或者抛出异常。

9. JUC 三大辅助类

9.1 概述

JUC 中提供了三种常用的辅助类,通过这些辅助类可以很好的解决线程数量过多时 Lock 锁的频繁操作。这三种辅助类为:

• CountDownLatch: 减少计数

• CyclicBarrier: 循环栅栏

• Semaphore: 信号灯

9.2 减少计数 CountDownLatch

CountDownLatch类可以设置一个计数器,然后通过 countDown 方法来进行 减 1 的操作,使用 await 方法等待计数器不大于 0,然后继续执行 await 方法之后的语句。

  • CountDownLatch 主要有两个方法,当一个或多个线程调用 await 方法时,这些线程会阻塞
  • 其它线程调用 countDown 方法会将计数器减 1(调用 countDown 方法的线程不会阻塞)。
  • 当计数器的值变为 0 时,因 await 方法阻塞的线程会被唤醒,继续执行。
public class CountDownLatchDemo {/*** 6 个同学陆续离开教室后值班同学才可以关门* @param args*/public static void main(String[] args) throws Exception{//定义一个数值为 6 的计数器CountDownLatch countDownLatch = new CountDownLatch(6);//创建 6 个同学for (int i = 1; i <= 6; i++) {new Thread(() ->{try{if(Thread.currentThread().getName().equals("同学 6")){Thread.sleep(2000);}System.out.println(Thread.currentThread().getName() + "离开了");//计数器减一,不会阻塞countDownLatch.countDown();}catch (Exception e){e.printStackTrace();}}, "同学 " + i).start();}//主线程 await 休息countDownLatch.await();//全部离开后自动唤醒主线程System.out.println("全部离开了,现在的计数器为" + countDownLatch.getCount());}
}

执行效果:

由于异步,使用CountDownLatch 来保证“同步”的  

//定义一个数值为 6 的计数器 CountDownLatch countDownLatch = new CountDownLatch(6);

// 主线程堵塞

countDownLatch.await();

9.3 循环栅栏 CyclicBarrier

由英文单词可以看出大概就是循环阻塞的意思,在使用中 CyclicBarrier 的构造方法第一个参数是目标障碍数,每次执行 CyclicBarrier 一次障碍数会加一,如果达到了目标障碍数,才会执行 cyclicBarrier.await()之后 的语句。可以将 CyclicBarrier 理解为加 1

操作 场景: 集齐 7 颗龙珠就可以召唤神龙 (达到七个阻塞的线程就执行复活愿望)

public class CyclicBarrierDemo {//定义神龙召唤需要的龙珠总数private final static int NUMBER = 7;/*** 集齐 7 颗龙珠就可以召唤神龙* @param args*/public static void main(String[] args) {//定义循环栅栏CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () ->{System.out.println("集齐" + NUMBER + "颗龙珠,现在召唤神龙!!!!!!!!!");});//定义 7 个线程分别去收集龙珠for (int i = 1; i <= 7; i++) {new Thread(()->{try {if(Thread.currentThread().getName().equals("龙珠 3 号")){System.out.println("龙珠 3 号抢夺战开始,孙悟空开启超级赛亚人模        式!");Thread.sleep(5000);System.out.println("龙珠 3 号抢夺战结束,孙悟空打赢了,拿到了龙珠 3
号!");}else{System.out.println(Thread.currentThread().getName() + "收集到
了!!!!");}cyclicBarrier.await();}catch (Exception e){e.printStackTrace();}}, "龙珠" + i + "号").start();}}

每次执行 cyclicBarrier.await()一次障碍数会加一,当其达到对象CyclicBarrier中的NUMBER次数时将自动唤醒主线程

9.4 信号灯 Semaphore

Semaphore的构造方法中传入的第一个参数是最大信号量(可以看成最大线程池),每个信号量初始化为一个最多只能分发一个许可证。使用 acquire 方 法获得许可证,release 方法释放许可

场景: 抢车位, 6 部汽车 3 个停车位

import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;public class SemaphoreDemo {/*** 抢车位, 10 部汽车 1 个停车位* @param args*/public static void main(String[] args) throws Exception {//定义 3 个停车位Semaphore semaphore = new Semaphore(3);//模拟 6 辆汽车停车for (int i = 1; i <= 6; i++) {Thread.sleep(100);//停车new Thread(() -> {try {semaphore.acquire();System.out.println(Thread.currentThread().getName() + "找车位 ing");TimeUnit.SECONDS.sleep(new Random().nextInt(5));System.out.println("----" + Thread.currentThread().getName() + "溜了溜了");} catch (Exception e) {e.printStackTrace();} finally {semaphore.release();}}, "汽车" + i).start();}}
}

执行效果

总结:

  1. CountDownLatch 数目明确,等量。
  2. CyclicBarrier 定量有富余,等积累到才触发。
  3. Semaphore 定量稀少,需要抢占。
  4. 应用领域不同,JUC三大辅助类为了解决线程资源争夺,线程池是为了解决线程开销

JUC并发编程之Callable接口、JUC三大辅助类相关推荐

  1. JUC并发编程之Java线程(二)

    二.Java线程 2.1 创建和运行线程 方法一:Thread创建线程方式: 继承Thread类 匿名内部类方式 public class CreateThread01 {public static ...

  2. Java 并发编程之 Callable 和 Future

    ExecutorService 执行完Callable 任务后,返回 Future 对象,Future 对象表示一个任务的生命周期,包含任务的状态和任务的结果对象. Future的get方法可以获得 ...

  3. JUC 高并发编程之JUC三大辅助类

    JUC 高并发编程之JUC三大辅助类 JUC 中提供了三种常用的辅助类,通过这些辅助类可以很好的解决线程数量过 多时 Lock 锁的频繁操作.这三种辅助类为: CountDownLatch: 减少计数 ...

  4. cyclicbarrier java_Java并发编程之CyclicBarrier和线程池的使用

    原标题:Java并发编程之CyclicBarrier和线程池的使用 下面我们来讲述一下线程池和CyclicBarrier的使用和对比. 一.场景描述 有四个游戏玩爱好者玩游戏,游戏中有三个关卡,每一个 ...

  5. java线程安全的set_Java并发编程之set集合的线程安全类你知道吗

    Java并发编程之-set集合的线程安全类 Java中set集合怎么保证线程安全,这种方式你知道吗? 在Java中set集合是 本篇是<凯哥(凯哥并发编程学习>系列之<并发集合系列& ...

  6. java 时间戳_Java并发编程之CAS三CAS的缺点 及解决办法

    Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...

  7. Java并发编程之CAS第三篇-CAS的缺点

    Java并发编程之CAS第三篇-CAS的缺点 通过前两篇的文章介绍,我们知道了CAS是什么以及查看源码了解CAS原理.那么在多线程并发环境中,的缺点是什么呢?这篇文章我们就来讨论讨论 本篇是<凯 ...

  8. zbb20180929 thread java并发编程之Condition

    java并发编程之Condition 引言 在java中,对于任意一个java对象,它都拥有一组定义在java.lang.Object上监视器方法,包括wait(),wait(long timeout ...

  9. python电路模型编程_14、python开发之路-并发编程之I/O模型

    十四.并发编程之I/O模型 http://www.cnblogs.com/linhaifeng/articles/7454717.html 1.模型介绍 1.1 IO种类 (1)* blocking ...

最新文章

  1. 自学Python从哪学方面入手?
  2. 10年后的计算机会是怎样的?
  3. ExtJS 等待两个/多个store加载完再执行操作
  4. Global.asax或IHttpModule实现屏蔽ip和图片防盗链
  5. 【Java类加载机制】深入加载器
  6. Go Web编程--应用数据库
  7. 算法 查找子节点_掌握着十大编程算法助你走上高手之路
  8. java字符串元素置于最前_java_java编程常用技术(推荐),一:将String字符串放在最前面 - phpStudy...
  9. vb全局热键的写法(占很少的资源)
  10. MFC 线程创建方式
  11. 大合集!2019-2020年目标跟踪资源全汇总(论文、模型代码、优秀实验室)
  12. 如何交叉编译fio并移植到ARM、IOT上
  13. 【nn.Parameter】Pytorch特征融合自适应权重设置(可学习权重使用)
  14. 清华计算机录取通知书,清华送出第一批录取通知书,这些被刷屏的学霸,有怎样的成长密码...
  15. 鼠标左键双击图标出现属性窗口的问题
  16. [机缘参悟-52]:交浅言深要因人而异
  17. 在OTFS学习中的一些总结
  18. ESP8266模块三种低功耗睡眠模式
  19. (附源码)电影选座订票app 毕业设计 011439
  20. nohup python

热门文章

  1. 卓医通项目后端架构介绍
  2. HTML——文本域标签(textarea)
  3. 使用springboot对linux进行操控
  4. EXCEL实现多个工作表的快速数据汇总分类
  5. HDLBits刷题-Multiplexers
  6. python校验两个json体
  7. 自己的博客终于上线了!
  8. Java实战案例一:图书借阅系统
  9. 非常好看notepad++主题和字体
  10. 发布一个JS图片阅览组件