热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[置顶]Java同步工具类总结

先谈谈闭锁和栅栏的区别:1.关键区别在于,所有线程必须同时到达栅栏位置,才能继续执行。2.闭锁用于等待某一个事件的发生,
先谈谈闭锁和栅栏的区别:

1.关键区别在于,所有线程必须同时到达栅栏位置,才能继续执行。

2.闭锁用于等待某一个事件的发生,举例:CountDownLatch中await方法等待计数器为零时,所有事件才可继续执行。而栅栏是等待其他线程到位,所有事件才可继续下一步。例如:几个家庭决定在某个地方集合:“所有人6:00在麦当劳碰头,到了以后要等其他人,之后再讨论下一步要做的事情”。


Semaphore(闭锁)

这个东西和之前的synchronized干的事差不多。
synchronized保证了,我管理的那部分代码同一时刻只有一个线程能访问
Semaphore保证了,我管理的那部分代码同一时刻最多可以有n个线程访问


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore; public class SemaphoreTest { public static void main(String[] args) { ExecutorService service &#61; Executors.newCachedThreadPool(); final Semaphore sp &#61; new Semaphore(3); for(int i&#61;0;i<10;i&#43;&#43;){ Runnable runnable &#61; new Runnable(){ public void run(){ try { sp.acquire(); } catch (InterruptedException e1) { e1.printStackTrace(); } System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "进入&#xff0c;当前已有" &#43; (3-sp.availablePermits()) &#43; "个并发"); try { Thread.sleep((long)(Math.random()*10000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "即将离开"); sp.release(); //下面代码有时候执行不准确&#xff0c;因为其没有和上面的代码合成原子单元 System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "已离开&#xff0c;当前已有" &#43; (3-sp.availablePermits()) &#43; "个并发"); } }; service.execute(runnable); } } }

 运行结果如下&#xff1a;


线程pool-1-thread-2进入&#xff0c;当前已有2个并发
线程pool-1-thread-1进入&#xff0c;当前已有2个并发
线程pool-1-thread-3进入&#xff0c;当前已有3个并发
线程pool-1-thread-1即将离开
线程pool-1-thread-1已离开&#xff0c;当前已有2个并发
线程pool-1-thread-4进入&#xff0c;当前已有3个并发
线程pool-1-thread-3即将离开
线程pool-1-thread-3已离开&#xff0c;当前已有2个并发
线程pool-1-thread-5进入&#xff0c;当前已有3个并发
线程pool-1-thread-2即将离开
线程pool-1-thread-2已离开&#xff0c;当前已有2个并发
线程pool-1-thread-6进入&#xff0c;当前已有3个并发
线程pool-1-thread-4即将离开
线程pool-1-thread-4已离开&#xff0c;当前已有2个并发
线程pool-1-thread-7进入&#xff0c;当前已有3个并发
线程pool-1-thread-5即将离开
线程pool-1-thread-5已离开&#xff0c;当前已有2个并发
线程pool-1-thread-8进入&#xff0c;当前已有3个并发
线程pool-1-thread-8即将离开
线程pool-1-thread-9进入&#xff0c;当前已有3个并发
线程pool-1-thread-8已离开&#xff0c;当前已有3个并发
线程pool-1-thread-6即将离开
线程pool-1-thread-6已离开&#xff0c;当前已有2个并发
线程pool-1-thread-10进入&#xff0c;当前已有3个并发
线程pool-1-thread-10即将离开
线程pool-1-thread-10已离开&#xff0c;当前已有2个并发
线程pool-1-thread-7即将离开
线程pool-1-thread-7已离开&#xff0c;当前已有1个并发
线程pool-1-thread-9即将离开
线程pool-1-thread-9已离开&#xff0c;当前已有0个并发

 参考链接&#xff1a;http://www.cnblogs.com/nullzx/archive/2016/03/12/5270233.html 


CountDownLatch &#xff08;闭锁&#xff09;

它保证了什么功能呢?其实和CycliBarrier也类似。

看下面这个图

这就是CycleBarrier,线程自己管理自己,大家看到人都到齐了,才继续走。


这个是CountDownLatch,由他人来协调进度。

例如跑步的时候,有个裁判,等所有的人都到齐了,他吹哨,然后大家开始跑,等所有人都跑完了,他才公布成绩。


import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class CountdownLatchTest { public static void main(String[] args) { ExecutorService service &#61; Executors.newCachedThreadPool(); final CountDownLatch cdOrder &#61; new CountDownLatch(1); final CountDownLatch cdAnswer &#61; new CountDownLatch(3); for(int i&#61;0;i<3;i&#43;&#43;){ Runnable runnable &#61; new Runnable(){ public void run(){ try { System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "正准备接受命令"); cdOrder.await(); System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "已接受命令"); Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "回应命令处理结果"); cdAnswer.countDown(); } catch (Exception e) { e.printStackTrace(); } } }; service.execute(runnable); } try { Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "即将发布命令"); cdOrder.countDown(); System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "已发送命令&#xff0c;正在等待结果"); cdAnswer.await(); System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "已收到所有响应结果"); } catch (Exception e) { e.printStackTrace(); } service.shutdown(); }
}

 运行结果如下


线程pool-1-thread-3正准备接受命令
线程pool-1-thread-1正准备接受命令
线程pool-1-thread-2正准备接受命令
线程main即将发布命令
线程main已发送命令&#xff0c;正在等待结果
线程pool-1-thread-3已接受命令
线程pool-1-thread-2已接受命令
线程pool-1-thread-1已接受命令
线程pool-1-thread-3回应命令处理结果
线程pool-1-thread-1回应命令处理结果
线程pool-1-thread-2回应命令处理结果
线程main已收到所有响应结果

 

CountDownLatch里面有个计数器,初始值就是new countdownlatch时传入的

wait方法会一直等待,直到计数器的值变为0

coutdown方法可以让计数器的值减一

 


CycleBarrier&#xff08;栅栏&#xff09;

CycleBarrier 能做到让n个线程互相等待,当n个线程都做到某一步后,再继续下一步。

例如下面的例子,5个人去旅游,设置abc三个中途节点,所有人都到达a之后在继续走向b,所有人都到达b,然后才继续走向c。

 


import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class CyclicBarrierTest { public static void main(String[] args) { ExecutorService service &#61; Executors.newCachedThreadPool(); final CyclicBarrier cb &#61; new CyclicBarrier(3); for(int i&#61;0;i<3;i&#43;&#43;){ Runnable runnable &#61; new Runnable(){ public void run(){ try { Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "即将到达集合地点1&#xff0c;当前已有" &#43; (cb.getNumberWaiting()&#43;1) &#43; "个已经到达&#xff0c;" &#43; (cb.getNumberWaiting()&#61;&#61;2?"都到齐了&#xff0c;继续走啊":"正在等候")); cb.await(); Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "即将到达集合地点2&#xff0c;当前已有" &#43; (cb.getNumberWaiting()&#43;1) &#43; "个已经到达&#xff0c;" &#43; (cb.getNumberWaiting()&#61;&#61;2?"都到齐了&#xff0c;继续走啊":"正在等候")); cb.await(); Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "即将到达集合地点3&#xff0c;当前已有" &#43; (cb.getNumberWaiting() &#43; 1) &#43; "个已经到达&#xff0c;" &#43; (cb.getNumberWaiting()&#61;&#61;2?"都到齐了&#xff0c;继续走啊":"正在等候")); cb.await(); } catch (Exception e) { e.printStackTrace(); } } }; service.execute(runnable); } service.shutdown(); }
}

运行结果如下&#xff1a;

 


线程pool-1-thread-2即将到达集合地点1&#xff0c;当前已有1个已经到达&#xff0c;正在等候
线程pool-1-thread-1即将到达集合地点1&#xff0c;当前已有2个已经到达&#xff0c;正在等候
线程pool-1-thread-3即将到达集合地点1&#xff0c;当前已有3个已经到达&#xff0c;都到齐了&#xff0c;继续走啊
线程pool-1-thread-1即将到达集合地点2&#xff0c;当前已有1个已经到达&#xff0c;正在等候
线程pool-1-thread-3即将到达集合地点2&#xff0c;当前已有2个已经到达&#xff0c;正在等候
线程pool-1-thread-2即将到达集合地点2&#xff0c;当前已有3个已经到达&#xff0c;都到齐了&#xff0c;继续走啊
线程pool-1-thread-1即将到达集合地点3&#xff0c;当前已有1个已经到达&#xff0c;正在等候
线程pool-1-thread-2即将到达集合地点3&#xff0c;当前已有2个已经到达&#xff0c;正在等候
线程pool-1-thread-3即将到达集合地点3&#xff0c;当前已有3个已经到达&#xff0c;都到齐了&#xff0c;继续走啊

 



Exchange&#xff08;栅栏&#xff09;

A线程有数据1,它需要与B线程的数据2做交换
B线程有数据2,它需要与A线程的数据1做交换

那么什么时候交换呢?得等AB都做好准备才行。


import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class ExchangerTest { public static void main(String[] args) { ExecutorService service &#61; Executors.newCachedThreadPool(); final Exchanger exchanger &#61; new Exchanger(); service.execute(new Runnable(){ public void run() { try { String data1 &#61; "zxx"; System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "正在把数据" &#43; data1 &#43;"换出去"); Thread.sleep((long)(Math.random()*10000)); String data2 &#61; (String)exchanger.exchange(data1); System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "换回的数据为" &#43; data2); }catch(Exception e){ } } }); service.execute(new Runnable(){ public void run() { try { String data1 &#61; "lhm"; System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "正在把数据" &#43; data1 &#43;"换出去"); Thread.sleep((long)(Math.random()*10000)); String data2 &#61; (String)exchanger.exchange(data1); System.out.println("线程" &#43; Thread.currentThread().getName() &#43; "换回的数据为" &#43; data2); }catch(Exception e){ } } }); }
}

 运行结果如下&#xff1a;

 


线程pool-1-thread-1正在把数据zxx换出去
线程pool-1-thread-2正在把数据lhm换出去
线程pool-1-thread-2换回的数据为zxx
线程pool-1-thread-1换回的数据为lhm

 


推荐阅读
  • 解决JAX-WS动态客户端工厂弃用问题并迁移到XFire
    在处理Java项目中的JAR包冲突时,我们遇到了JaxWsDynamicClientFactory被弃用的问题,并成功将其迁移到org.codehaus.xfire.client。本文详细介绍了这一过程及解决方案。 ... [详细]
  • 本文详细介绍如何在VSCode中配置自定义代码片段,使其具备与IDEA相似的代码生成快捷键功能。通过具体的Java和HTML代码片段示例,展示配置步骤及效果。 ... [详细]
  • 本文介绍如何使用布局文件在Android应用中排列多行TextView和Button,使其占据屏幕的特定比例,并提供示例代码以帮助理解和实现。 ... [详细]
  • Startup 类配置服务和应用的请求管道。Startup类ASP.NETCore应用使用 Startup 类,按照约定命名为 Startup。 Startup 类:可选择性地包括 ... [详细]
  • 本文详细探讨了HTML表单中GET和POST请求的区别,包括它们的工作原理、数据传输方式、安全性及适用场景。同时,通过实例展示了如何在Servlet中处理这两种请求。 ... [详细]
  • 本题通过将每个矩形视为一个节点,根据其相对位置构建拓扑图,并利用深度优先搜索(DFS)或状态压缩动态规划(DP)求解最小涂色次数。本文详细解析了该问题的建模思路与算法实现。 ... [详细]
  • 本题探讨如何通过最大流算法解决农场排水系统的设计问题。题目要求计算从水源点到汇合点的最大水流速率,使用经典的EK(Edmonds-Karp)和Dinic算法进行求解。 ... [详细]
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 本次考试于2016年10月25日上午7:50至11:15举行,主要涉及数学专题,特别是斐波那契数列的性质及其在编程中的应用。本文将详细解析考试中的题目,并提供解题思路和代码实现。 ... [详细]
  • 配置Windows操作系统以确保DAW(数字音频工作站)硬件和软件的高效运行可能是一个复杂且令人沮丧的过程。本文提供了一系列专业建议,帮助你优化Windows系统,确保录音和音频处理的流畅性。 ... [详细]
  • 深入理解Shell脚本编程
    本文详细介绍了Shell脚本编程的基础概念、语法结构及其在操作系统中的应用。通过具体的示例代码,帮助读者掌握如何编写和执行Shell脚本。 ... [详细]
  • 本文详细介绍了网络存储技术的基本概念、分类及应用场景。通过分析直连式存储(DAS)、网络附加存储(NAS)和存储区域网络(SAN)的特点,帮助读者理解不同存储方式的优势与局限性。 ... [详细]
  • 本文详细介绍了 org.apache.commons.io.IOCase 类中的 checkCompareTo() 方法,通过多个代码示例展示其在不同场景下的使用方法。 ... [详细]
  • JavaScript 基础语法指南
    本文详细介绍了 JavaScript 的基础语法,包括变量、数据类型、运算符、语句和函数等内容,旨在为初学者提供全面的入门指导。 ... [详细]
  • 异常要理解Java异常处理是如何工作的,需要掌握一下三种异常类型:检查性异常:最具代表性的检查性异常是用户错误或问题引起的异常ÿ ... [详细]
author-avatar
Jacky麦麦9
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有