前言

之前学多线程的时候没有学习线程的同步工具类(辅助类)。ps:当时觉得暂时用不上,认为是挺高深的知识点就没去管了..

在前几天,朋友发了一篇比较好的Semaphore文章过来,然后在浏览博客的时候又发现面试还会考,那还是挺重要的知识点。于是花了点时间去了解一下。

Java为我们提供了三个同步工具类

  • CountDownLatch(闭锁)
  • CyclicBarrier(栅栏)
  • Semaphore(信号量)

这几个工具类其实说白了就是为了能够更好控制线程之间的通讯问题~

一、CountDownLatch

1.1CountDownLatch简介

  • A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

简单来说:CountDownLatch是一个同步的辅助类,允许一个或多个线程一直等待直到其它线程完成它们的操作。

它常用的API其实就两个:await()countDown()

使用说明:

  • count初始化CountDownLatch,然后需要等待的线程调用await方法。await方法会一直受阻塞直到count=0。而其它线程完成自己的操作后,调用countDown()使计数器count减1。当count减到0时,所有在等待的线程均会被释放
  • 说白了就是通过count变量来控制等待,如果count值为0了(其他线程的任务都完成了),那就可以继续执行。

1.2CountDownLatch例子

例子:3y现在去做实习生了,其他的员工还没下班,3y不好意思先走,等其他的员工都走光了,3y再走。


import java.util.concurrent.CountDownLatch; public class Test { public static void main(String[] args) { final CountDownLatch countDownLatch = new CountDownLatch(5); System.out.println("现在6点下班了....."); // 3y线程启动
new Thread(new Runnable() {
@Override
public void run() { try {
// 这里调用的是await()不是wait()
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("...其他的5个员工走光了,3y终于可以走了");
}
}).start(); // 其他员工线程启动
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("员工xxxx下班了");
countDownLatch.countDown();
}
}).start();
}
}
}

输出结果:

再写个例子:3y现在负责仓库模块功能,但是能力太差了,写得很慢,别的员工都需要等3y写好了才能继续往下写。


import java.util.concurrent.CountDownLatch; public class Test { public static void main(String[] args) { final CountDownLatch countDownLatch = new CountDownLatch(1); // 3y线程启动
new Thread(new Runnable() {
@Override
public void run() { try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("3y终于写完了");
countDownLatch.countDown(); }
}).start(); // 其他员工线程启动
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("其他员工需要等待3y");
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("3y终于写完了,其他员工可以开始了!");
}
}).start();
}
}
}

输出结果:

参考资料:

二、CyclicBarrier

2.1CyclicBarrier简介

  • A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other. The barrier is called cyclic because it can be re-used after the waiting threads are released.

简单来说:CyclicBarrier允许一组线程互相等待,直到到达某个公共屏障点。叫做cyclic是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用(对比于CountDownLatch是不能重用的)

使用说明:

  • CountDownLatch注重的是等待其他线程完成,CyclicBarrier注重的是:当线程到达某个状态后,暂停下来等待其他线程,所有线程均到达以后,继续执行。

2.2CyclicBarrier例子

例子:3y和女朋友约了去广州夜上海吃东西,由于3y和3y女朋友住的地方不同,自然去的路径也就不一样了。于是他俩约定在体育西路地铁站集合,约定等到相互见面的时候就发一条朋友圈。


import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier; public class Test { public static void main(String[] args) { final CyclicBarrier CyclicBarrier = new CyclicBarrier(2);
for (int i = 0; i < 2; i++) { new Thread(() -> { String name = Thread.currentThread().getName();
if (name.equals("Thread-0")) {
name = "3y";
} else {
name = "女朋友";
}
System.out.println(name + "到了体育西");
try { // 两个人都要到体育西才能发朋友圈
CyclicBarrier.await();
// 他俩到达了体育西,看见了对方发了一条朋友圈:
System.out.println("跟" + name + "去夜上海吃东西~");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}

测试结果:

玩了一天以后,各自回到家里,3y和女朋友约定各自洗澡完之后再聊天


import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier; public class Test { public static void main(String[] args) { final CyclicBarrier CyclicBarrier = new CyclicBarrier(2);
for (int i = 0; i < 2; i++) { new Thread(() -> { String name = Thread.currentThread().getName();
if (name.equals("Thread-0")) {
name = "3y";
} else {
name = "女朋友";
}
System.out.println(name + "到了体育西");
try { // 两个人都要到体育西才能发朋友圈
CyclicBarrier.await();
// 他俩到达了体育西,看见了对方发了一条朋友圈:
System.out.println("跟" + name + "去夜上海吃东西~"); // 回家
CyclicBarrier.await();
System.out.println(name + "洗澡"); // 洗澡完之后一起聊天
CyclicBarrier.await(); System.out.println("一起聊天"); } catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}

测试结果:

参考资料:

三、Semaphore

3.1Semaphore简介

Semaphores are often used to restrict the number of threads than can access some (physical or logical) resource.


  • A counting semaphore. Conceptually, a semaphore maintains a set of permits. Each {@link #acquire} blocks if necessary until a permit is available, and then takes it. Each {@link #release} adds a permit,potentially releasing a blocking acquirer.However, no actual permit objects are used; the {@code Semaphore} just
    keeps a count of the number available and acts accordingly.

Semaphore(信号量)实际上就是可以控制同时访问的线程个数,它维护了一组"许可证"

  • 当调用acquire()方法时,会消费一个许可证。如果没有许可证了,会阻塞起来
  • 当调用release()方法时,会添加一个许可证。
  • 这些"许可证"的个数其实就是一个count变量罢了~

3.2Semaphore例子

3y女朋友开了一间卖酸奶的小店,小店一次只能容纳5个顾客挑选购买,超过5个就需要排队啦~~~



import java.util.concurrent.Semaphore;

public class Test {

    public static void main(String[] args) {

        // 假设有50个同时来到酸奶店门口
int nums = 50; // 酸奶店只能容纳10个人同时挑选酸奶
Semaphore semaphore = new Semaphore(10); for (int i = 0; i < nums; i++) {
int finalI = i;
new Thread(() -> {
try {
// 有"号"的才能进酸奶店挑选购买
semaphore.acquire(); System.out.println("顾客" + finalI + "在挑选商品,购买..."); // 假设挑选了xx长时间,购买了
Thread.sleep(1000); // 归还一个许可,后边的就可以进来购买了
System.out.println("顾客" + finalI + "购买完毕了...");
semaphore.release(); } catch (InterruptedException e) {
e.printStackTrace();
}
}).start(); } }
}

输出结果:

反正每次只能5个客户同时进酸奶小店购买挑选。

参考资料:

四、总结

Java为我们提供了三个同步工具类

  • CountDownLatch(闭锁)

    • 某个线程等待其他线程执行完毕后,它才执行(其他线程等待某个线程执行完毕后,它才执行)
  • CyclicBarrier(栅栏)
    • 一组线程互相等待至某个状态,这组线程再同时执行。
  • Semaphore(信号量)
    • 控制一组线程同时执行

本文简单的介绍了一下这三个同步工具类是干嘛用的,要深入还得看源码或者借鉴其他的资料。

java中重要的多线程工具类的更多相关文章

  1. java中的Arrays这个工具类你真的会用吗

    Java源码系列三-工具类Arrays ​ 今天分享java的源码的第三弹,Arrays这个工具类的源码.因为近期在复习数据结构,了解到Arrays里面的排序算法和二分查找等的实现,收益匪浅,决定研读 ...

  2. java中excel导入\导出工具类

    1.导入工具 package com.linrain.jcs.test; import jxl.Cell; import jxl.Sheet; import jxl.Workbook; import ...

  3. java中定义一个CloneUtil 工具类

    其实所有的java对象都可以具备克隆能力,只是因为在基础类Object中被设定成了一个保留方法(protected),要想真正拥有克隆的能力, 就需要实现Cloneable接口,重写clone方法.通 ...

  4. Java中的集合Collections工具类(六)

    操作集合的工具类Collections Java提供了一个操作Set.List和Map等集合的工具类:Collections,该工具类里提供了大量方法对集合元素进行排序.查询和修改等操作,还提供了将集 ...

  5. java中文件操作的工具类

    代码: package com.lky.pojo; import java.io.BufferedReader; import java.io.BufferedWriter; import java. ...

  6. 在JAVA中自定义连接数据库的工具类

    为什么要自定义数据库连接的工具类: 在开发中,我们在对数据库进行操作时,必须要先获取数据库的连接,在上一篇随笔中提到的获取数据库连接的步骤为: 1.定义好4个参数并赋值 2.加载驱动类 3.获取数据库 ...

  7. java中IO写文件工具类

    以下是一些依据经常使用java类进行组装的对文件进行操作的类,平时,我更喜欢使用Jodd.io中提供的一些对文件的操作类,里面的方法写的简单易懂. 当中jodd中提供的JavaUtil类中提供的方法足 ...

  8. java中常用的并发工具类

    · 1. 等待多线程完成的CountDownLatch 构造函数接收一个int类型的参数作为计数器,如果想等待N个点,就传入N.当调用CountDownLatch的countDown方法时,N就会减一 ...

  9. Java中Date类型的工具类

    package com.mytripod.util; import java.text.DateFormat; import java.text.SimpleDateFormat; import ja ...

随机推荐

  1. 将Tensor输出到文件

    ) local file = io.open('/home/xbwang/Desktop/part2original','a') ,length do number = part2[j] file:w ...

  2. 利用MATLAB软件对数码相机进行检校

    分享资料:https://pan.baidu.com/s/1FQb-ttLJNJKlMzu-0RjBsw.内部包含张正友的经典论文等文献,官网的checkerboardPattern等.

  3. 1555: Inversion Sequence (通过逆序数复原序列 vector的骚操作!!!)

    1555: Inversion Sequence Submit Page    Summary    Time Limit: 2 Sec     Memory Limit: 256 Mb     Su ...

  4. BFC (Block formatting context)

     一:BFC 是什么      MDN解释: A block formatting context is a part of a visual CSS rendering of a Web page. ...

  5. 学习JavaSE 数组

    一维数组 基本概念 1.数组中只允许放同一种类型(可以是父子关系). 2.数组即对象. 例: int[ ] arrs={0,1,2};//arrs即一个对象. 3.数组是定长的,不可以增加或者减少. ...

  6. Linux入门基础(一):Linux基本操作

    命令行BASH基本操作 Shell 用户不能直接操作内核,所以用户操作通过shell传递给内核 shell分为两种 : GUI 图形界面 (linux一般是GNOME) CLI 命令行界面 (linu ...

  7. 关于mysql中GROUP_CONCAT函数的使用

    偶然看到公司存储过程中有个字符串拼接的函数,改bug过程中使用到了,还挺有用的,于是记录下来方便记忆,帮助有需要的人. 这是我需要整理的串,他是调用了一个存储过程,传入组织机构的id和迭代层数,返回来 ...

  8. [笔记] FMX 移动平台 TWebBrowser 问题

    FMX 移动平台下的 TWebBrowser 有一问题: 某些机子当 WebBrowser.Visible := False; 后,依然留在全屏,虽然看不见,但无法点击操作. 解决:用 WebBrow ...

  9. go 交叉编译,部署

    go web 部署 交叉编译 go 语言有个强大的地方就是 交叉编译 windows --cmd 设置环境变量-mac SET CGO_ENABLED=0 SET GOOS=darwin SET GO ...

  10. leetcode之转置矩阵

    转置矩阵 题目描述: 给定一个矩阵 A, 返回 A 的转置矩阵. 矩阵的转置是指将矩阵的主对角线翻转,交换矩阵的行索引与列索引. 示例 1: 输入:[[1,2,3],[4,5,6],[7,8,9]] ...