前言

之前学多线程的时候没有学习线程的同步工具类(辅助类)。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. js 正则验证

    Html 代码如下: <table> <tr> <td>匹配正整数:</td> <td><input type="text& ...

  2. PAT乙级1027

    1027 打印沙漏 (20 分)   本题要求你写个程序把给定的符号打印成沙漏的形状.例如给定17个“*”,要求按下列格式打印 ***** *** * *** ***** 所谓“沙漏形状”,是指每行输 ...

  3. SpringMVC的应用与工作流程解析

    一:SpringMVC是什么 SpringMVC只是Spring的一个子框架,作用学过Struts2的应该很好理解,他们都是MVC的框架.学他就是用来代替Struts2的,那么为什么不用Struts2 ...

  4. Spring3学习笔记--spring概述

    Spring 是什么? Spring 是一个开源的轻量级 Java SE( Java 标准版本)/Java EE( Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发.在传统应用程序 ...

  5. EasyX_无法填充圆颜色的问题

    官网:https://www.easyx.cn/ 在线帮助文档:https://docs.easyx.cn/ 目标:生成一个边框为黄色,填充为蓝色的圆 遇到的问题:使用以下代码,只能生成边框为黄色的圆 ...

  6. 第一次作业:基于Linux 4.5的进程模型与调度器分析

    1.操作系统是怎么组织进程的? 1.1什么是线程,什么是进程: 刚接触时可能经常会将这两个东西搞混.简单一点的说,进程是一个大工程,线程则是这个大工程中每个小地方需要做的东西(在linux下看作&qu ...

  7. mac php项目除了首页全飘not found

    1.httpd.conf配置文件中加载了mod_rewrite.so模块2.AllowOverride None 将None改为 All DocumentRoot "/Library/Web ...

  8. PostgreSQL的Checkpoint 发生的时机

    磨砺技术珠矶,践行数据之道,追求卓越价值 回到上一级页面:PostgreSQL基础知识与基本操作索引页    回到顶级页面:PostgreSQL索引页 官方说明来自: http://www.postg ...

  9. CUDA基础介绍

    一.GPU简介 1985年8月20日ATi公司成立,同年10月ATi使用ASIC技术开发出了第一款图形芯片和图形卡,1992年4月ATi发布了Mach32图形卡集成了图形加速功能,1998年4月ATi ...

  10. 给浏览器和各种软件配置 http https socks5 代理 proxy

    只需要像在 idea 里一样,配置好sr的本地代理ip:127.0.0.1   本地代理端口:1080 浏览器和软件的流量即可走 sr ,就能被 sr 代理了 用上代理之后,确实快了好多,这里是在打开 ...