Callable接口和JUC辅助类

Callable接口:

回顾:

创建线程的四种方式:

  1. 继承Thread
  2. 实现runnable接口
  3. 实现callable接口
  4. 使用线程池

之前的文章:多线程编程1-定义理解与三种实现方式

Runnable和Callable接口的差异:

  1. Runnable无返回值,Callable有返回值
  2. Runnable不抛异常,Callable抛异常
  3. 实现名称不同,Runnable是run方法,Callable是call方法
class MyThread1 implements Runnable{

    @Override
public void run() { }
} class MyThread2 implements Callable{ @Override
public Integer call() throws Exception {
return 200;
}
}

Runnable 接口实现类FutureTask

FutureTask构造可以传递callable

这是类的继承结构:

别名:可取消的异步,简单的理解是当主线程中存在耗时高的任务时,可以单开一个子线程处理,主线程处理耗时少的任务,最终汇合在一起。

需要注意的是,使用FutureTask当得到第一次结果后,第二次获取时直接返回结果,也可以说所有的任务只汇总一次。

JUC辅助类:

CountDownLatch(减少计数)

定义:一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier

CountDownLatch 是一个通用同步工具,它有很多用途。将计数 1 初始化的 CountDownLatch 用作一个简单的开/关锁存器,或入口:在通过调用 countDown() 的线程打开入口前,所有调用 await 的线程都一直在入口处等待。用 N 初始化的 CountDownLatch 可以使一个线程在 N 个线程完成某项操作之前一直等待,或者使其在某项操作完成 N 次之前一直等待

/**
* 问题,当六个人走出教室,则班长锁门
*/
public class CountDownLatch07 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(6);
for(int i = 1; i <= 6; i++){
new Thread(() ->{
System.out.println(Thread.currentThread().getName()+" 号同学走出教室");
latch.countDown();
},String.valueOf(i)).start();
}
latch.await();
System.out.println(Thread.currentThread().getName()+"班长锁门");
}
}

其使用的方法,CountDownLatch latch = new CountDownLatch(6)、latch.countDown()、latch.await();

CyclicBarrier(循环栅栏)也可以实现CountDownLatch效果,CyclicBarrier在所有线程执行完毕之后是可以重用的。

CyclicBarrier(循环栅栏)

源码定义:

一种同步辅助工具,它允许一组线程全部等待彼此到达公共屏障点。 CyclicBarriers 在涉及固定大小的线程组的程序中很有用,这些线程必须偶尔相互等待。 屏障被称为循环的,因为它可以在等待线程被释放后重新使用。

简单的理解,当达到设置的要求后,执行特定的内容,相当于监听器;

实例代码:

public class JucUtils {
private static final Integer NUMBER = 7;
public static void main(String[] args) {
//设置资源要求,达到后所需要执行的任务
CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, () -> {
System.out.println("资源达到要求!");
});
//对设置的目标前进
for (int i = 1; i <= 7; i++) {
int finalI = i;
new Thread(()->{
try {
System.out.println("资源正在收集:"+ Thread.currentThread().getName());
//等待,当等待的线程数量到达设置的值,调用执行任务并释放这些线程。
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}

感兴趣的可以看看源码:

-------------------------CyclicBarrier--------------------
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties; //设置临界值
this.barrierCommand = barrierAction;
}
----------------------------await-----------------------
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
//------------------dowait部分代码-------------------
final Generation g = generation; if (g.broken)
throw new BrokenBarrierException(); if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
} int index = --count; //每次等待,所需资源-1;
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
} //------nextGeneration----------
private void nextGeneration() {
// signal completion of last generation
trip.signalAll(); //唤醒线程
// set up next generation
count = parties;
generation = new Generation();
}

Semaphore(信号灯)

如果对操作系统有所了解的话,该工具类就是信号量+pv操作的集合,对信号量的操作只有三种,初始化、p操作、v操作,其中信号量就是Semaphore初始化的(某种资源的数量),p操作对应的是semaphore.acquire(),信号量--,v操作对应的semaphore.release(),信号量++,当Semaphore初始化唯1时,则为互斥资源。

package com.JUC;

import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit; /**
* 类比操作系统的中信号量PV操作
*/
public class Semaphore07 {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for(int i = 1; i <= 6; i++){
new Thread(()->{
try {
semaphore.acquire(); //加锁
System.out.println(Thread.currentThread().getName()+" 抢到了车位");
TimeUnit.SECONDS.sleep(new Random().nextInt(5));//随机时间停车
System.out.println(Thread.currentThread().getName()+"-------离开了车位"); } catch (InterruptedException e) {
e.printStackTrace();
}finally{
semaphore.release(); //解锁
}
},String.valueOf(i)).start();
}
}
}

JUC之Callable接口回顾和JUC辅助类的更多相关文章

  1. 基于接口回调详解JUC中Callable和FutureTask实现原理

    Callable接口和FutureTask实现类,是JUC(Java Util Concurrent)包中很重要的两个技术实现,它们使获取多线程运行结果成为可能.它们底层的实现,就是基于接口回调技术. ...

  2. JUC之Lock接口以及Synchronized回顾

    Lock接口 Synchronized关键字回顾: 多线程编程步骤(上): 创建资源类,在资源类创建属性和操作方法 创建多个线程,调用资源类的操作方法 创建线程的四种方式: 继承Thread 实现Ru ...

  3. JUC—Callable接口

    一.callable接口是什么? 面试题: 获得多线程的方法几种? 正确答案如下: 传统的 是继承thread类和实现runnable接口, java5以后又有实现 callable接口 和 java ...

  4. 实现多线程的方式之实现Callable接口

    package com.hls.juc; import java.util.concurrent.Callable;import java.util.concurrent.ExecutionExcep ...

  5. 实现Callable接口创建线程

    创建执行线程有四种方式: 实现implements接口创建线程 继承Thread类创建线程 实现Callable接口,通过FutureTask包装器来创建线程 使用线程池创建线程 下面介绍通过实现Ca ...

  6. 创建执行线程方式三:实现Callable接口

    Callable接口 ① Java 5.0 在 java.util.concurrent 提供了一个新的创建执行 线程的方式:Callable 接口② Callable 接口类似于 Runnable, ...

  7. Callable接口、Runable接口、Future接口

    1. Callable与Runable区别 Java从发布的第一个版本开始就可以很方便地编写多线程的应用程序,并在设计中引入异步处理.Thread类.Runnable接口和Java内存管理模型使得多线 ...

  8. 线程池的应用及Callable接口的使用

    public interface Executor { /** * Executes the given command at some time in the future.  The comman ...

  9. [改善Java代码]异步运算考虑使用Callable接口

    多线程有两种实现方式: 一种是实现Runnable接口,另一种是继承Thread类,这两种方式都有缺点,run方法没有返回值,不能抛出异常(这两个缺点归根到底是Runable接口的缺陷,Thread也 ...

随机推荐

  1. Go语言核心36讲(Go语言实战与应用二十五)--学习笔记

    47 | 基于HTTP协议的网络服务 我们在上一篇文章中简单地讨论了网络编程和 socket,并由此提及了 Go 语言标准库中的syscall代码包和net代码包. 我还重点讲述了net.Dial函数 ...

  2. Redis | 第12章 Sentinel 哨兵模式《Redis设计与实现》

    目录 前言 1. 启动并初始化 Sentinel 2. Sentinel 与服务器间的默认通信 2.1 获取主服务器信息 2.2 获取从服务器信息 2.3 向主服务器和从服务器发送信息 3. 接受来自 ...

  3. shell脚本 Linux系统巡检

    一.简介 源码地址 日期:2018/4/12 介绍:非常详细的Linux系统巡检脚本,截图为一部分输出 效果图: 二.使用 适用:centos6+ 语言:中文 注意:无 下载 wget https:/ ...

  4. 转:builder模式分析

    建造者模式 11.1 变化是永恒的 又是一个周三,快要下班了,老大突然拉住我,喜滋滋地告诉我:"牛叉公司很满意我们做的模型,又签订了一个合同,把奔驰.宝马的车辆模型都交给我们公司制 作了,不 ...

  5. MySQL慢日志优化

    慢日志的性能问题 造成 I/O 和 CPU 资源消耗:慢日志通常会扫描大量非目的的数据,自然就会造成 I/O 和 CPU 的资源消耗,影响到其他业务的正常使用,有可能因为单个慢 SQL 就能拖慢整个数 ...

  6. C语言程序与设计:统计素数并求和

    目录 C语言程序与设计:统计素数并求和 1.题目要求 2.分析 3.代码 C语言程序与设计:统计素数并求和 1.题目要求 输入两个正整数 m 和 n(1≤m≤n≤500),统计给定整数 m 和 n 区 ...

  7. Landsat 现有 Analysis Ready Data (ARD) 数据介绍

    Global Web-Enabled Landsat Data (GWELD)[1] NASA 原先的 Web-Enabled Landsat Data Conterminous U.S. Seaso ...

  8. 模仿写了一个摸鱼APP解决原作者的问题

    前几天见到微博里有人提到摸鱼APP,发现需要在windows store下载才可以使用,文件约100多M左右的样子,自已没有登录微软Store的习惯.想想只有一个介面,没有必要这么大,于是,自已动手写 ...

  9. SSM——Spring框架

    Spring概念 什么是Spring Spring两大核心 1.IOC 所谓的IOC称之为控制反转,简单来说就是将对象的创建的权利及对象的生命周期的管理过程交由Spring框架来处理,从此在开发过程中 ...

  10. Java 常用类库一,main方法传参String[] args;获取输入Scanner ;hasNext();hasNextInt()

    1. main方法传参 package com.zmd.common_class_libraries; /** 给mian方法传参测试 */ public class MainArgsTest { p ...