Java中的线程--线程中的工具

  这主要想写一下Java中的jdk提供的一些线程中的工具,

一、semaphore信号灯

Semaphore可以维护当前访问自身的线程个数,并提供了同步机制,使用Semaphore可以控制同时访问资源的线程的个数。例如,实现一个文件允许访问的并发数。

Semaphore实现的功能就类似厕所5个坑,假如有10个人要上厕所,那么同时可以有多少人上厕所呢?同时只能有5个人能够占用,当5个人中的任何一个让开后,其中在等待的另外5个中的一个就可以占用了。

单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。

代码如下:

 1 import java.util.concurrent.ExecutorService;
 2 import java.util.concurrent.Executors;
 3 import java.util.concurrent.Semaphore;
 4
 5 /**
 6  * @className: SemaphoreTest
 7  * @description: Semaphore信号灯测试实例
 8  * @author: ssc
 9  * @date: 2019年6月18日 下午9:01:33
10  */
11 public class SemaphoreTest {
12
13     public static void main(String[] args) {
14
15         ExecutorService services = Executors.newCachedThreadPool();
16         Semaphore sp = new Semaphore(3);
17
18         for (int i = 0; i < 10; i++) {
19             Runnable runnable = new Runnable() {
20                 @Override
21                 public void run() {
22                     try {
23                         // 查询信号灯的状态 是否可以进入
24                         sp.acquire();
25                         System.out.println("线程 " + Thread.currentThread().getName() + "进入,当前已有"
26                                 + (3 - sp.availablePermits()) + " 并发");
27                         Thread.sleep((long) (Math.random() * 10000));
28                         System.out.println("线程 " + Thread.currentThread().getName() + " 即将离开");
29                         // 释放信号灯 让别的线程进入
30                         sp.release();
31                         System.out.println("线程 " + Thread.currentThread().getName() + "已离开,当前已有"
32                                 + (3 - sp.availablePermits()) + " 并发");
33                     } catch (Exception e) {
34                         e.printStackTrace();
35                     }
36                 }
37             };
38             services.execute(runnable);
39         }
40     }
41
42 }

二、CyclicBarrier循环路障

字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。我们暂且把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。

使用代码如下:

 1 import java.util.concurrent.CyclicBarrier;
 2 import java.util.concurrent.ExecutorService;
 3 import java.util.concurrent.Executors;
 4
 5 /**
 6  * @className: CyclicBarrier
 7  * @description: 线程中的循环路障工具类
 8  * @author: ssc
 9  * @date: 2019年6月18日 下午9:58:36
10  */
11 public class CyclicBarrierTest {
12
13     public static void main(String[] args) {
14         ExecutorService services = Executors.newCachedThreadPool();
15         // 创建 路障实例对象
16         CyclicBarrier cb = new CyclicBarrier(3);
17
18         for (int i = 0; i < 3; i++) {
19             Runnable runnable = new Runnable() {
20                 @Override
21                 public void run() {
22                     try {
23
24                         Thread.sleep((long) Math.random() * 10000);
25                         System.out.println("线程 " + Thread.currentThread().getName() + "即将到达集合地点1,当前已有"
26                                 + (cb.getNumberWaiting()) + " 到达,正在等候...");
27                         // 到此如果没有达到公共屏障点,则该线程处于等待状态,如果达到公共屏障点则所有处于等待的线程都继续往下运行
28                         cb.await();
29
30                         Thread.sleep((long) Math.random() * 10000);
31                         System.out.println("线程 " + Thread.currentThread().getName() + "即将到达集合地点2,当前已有"
32                                 + (cb.getNumberWaiting()) + " 到达,正在等候...");
33                         cb.await();
34
35                         Thread.sleep((long) Math.random() * 10000);
36                         System.out.println("线程 " + Thread.currentThread().getName() + "即将到达集合地点3,当前已有"
37                                 + (cb.getNumberWaiting()) + " 都到齐了, 继续走啊!");
38                         cb.await();
39
40                     } catch (Exception e) {
41                         e.printStackTrace();
42                     }
43                 }
44             };
45             services.execute(runnable);
46         }
47         services.shutdown();
48     }
49
50 }

 三、CountDownLatch倒计时计时器

CountDownLatch犹如倒计时计时器,调用CountDownLatch对象的countDown方法就将计时器减去1。当计时器到达0时,则所有等待着或者单个等待着开始执行。

可以实现一个人或者是多个人等待其他人通知他,可以实现一个人通知多个人的效果。类似裁判一声口令,运动员同时开始奔跑,或者所有运动员都跑到终点后裁判才可以通知结果。还可以实现一个计划需要多个领导签字后才可以继续向下实施的情况

示例代码如下:

 1 import java.util.concurrent.CountDownLatch;
 2 import java.util.concurrent.ExecutorService;
 3 import java.util.concurrent.Executors;
 4
 5 /**
 6  * @className: CountDownLatchTest
 7  * @description: 线程中的计时器类
 8  * @author: ssc
 9  * @date: 2019年6月20日 下午9:13:40
10  */
11 public class CountDownLatchTest {
12
13     public static void main(String[] args) {
14         ExecutorService services = Executors.newCachedThreadPool();
15         // 主线程中的计时器 相当于赛跑中的裁判
16         CountDownLatch cdOrder = new CountDownLatch(1);
17         // 新建线程的计时器 相当于赛跑中的运动员
18         CountDownLatch cdAnswer = new CountDownLatch(3);
19
20         for (int i = 0; i < 3; i++) {
21             Runnable runnable = new Runnable() {
22                 @Override
23                 public void run() {
24                     try {
25                         System.out.println("线程 " + Thread.currentThread().getName() + "正准备接受命令...");
26                         // 等待计时器上技数值 归0 才开始执行 相当于运动员等待裁判的起跑枪声
27                         cdOrder.await();
28                         System.out.println("线程 " + Thread.currentThread().getName() + "已经接受命令...");
29                         Thread.sleep((long) (Math.random() * 10000));
30                         System.out.println("线程 " + Thread.currentThread().getName() + "等待命令处理结果...");
31                         // 计时器上的数值减去1 相当于运动员相继跑到终点 等待裁判宣布最终结果
32                         cdAnswer.countDown();
33                     } catch (Exception e) {
34                         // TODO Auto-generated catch block
35                         e.printStackTrace();
36                     }
37                 }
38             };
39             services.execute(runnable);
40         }
41         services.shutdown();
42
43         try {
44             Thread.sleep((long) (Math.random() * 10000));
45             System.out.println("线程 " + Thread.currentThread().getName() + "即将发布命令...");
46             // 计数器上的 技数的值减去1 这个计数器本身就是 1 就相当于裁判的起跑枪声,只有这个计时器到0,其他线程才开始执行
47             cdOrder.countDown();
48             System.out.println("线程 " + Thread.currentThread().getName() + "已经发布命令,正在等待结果...");
49             // 只有另外三个线程都执行到这里,分别将计时器的数值减去1,下面的代码才执行,相当于裁判等运动员都通过终点,才宣布结果
50             cdAnswer.await();
51             System.out.println("线程 " + Thread.currentThread().getName() + "已收到所有响应结果...");
52         } catch (Exception e) {
53             e.printStackTrace();
54         }
55     }
56 }

四、Exchanger工具类

用于实现两个人之间的数据交换,每个人在完成一件事物后,想与对方交换数据,第一个拿出数据的人将一直等待第二个人拿出数据来时,才会互相交换

示例代码如下:

 1 import java.util.concurrent.Exchanger;
 2 import java.util.concurrent.ExecutorService;
 3 import java.util.concurrent.Executors;
 4
 5 /**
 6  * @className: ExchangerTest
 7  * @description: Exchanger工具类的示例
 8  * @author: ssc
 9  * @date: 2019年6月20日 下午10:00:19
10  */
11 public class ExchangerTest {
12
13     public static void main(String[] args) {
14         ExecutorService services = Executors.newCachedThreadPool();
15
16         Exchanger exchanger = new Exchanger();
17
18         services.execute(new Runnable() {
19             @Override
20             public void run() {
21                 try {
22                     String data1 = "abc";
23                     System.out.println("线程" + Thread.currentThread().getName() + "正准备把数据" + data1 + "换出去");
24                     Thread.sleep((long) (Math.random() * 10000));
25                     // 进行数据的交换
26                     String data2 = (String) exchanger.exchange(data1);
27                     System.out.println("线程" + Thread.currentThread().getName() + "换回的数据是" + data2);
28                 } catch (InterruptedException e) {
29                     // TODO Auto-generated catch block
30                     e.printStackTrace();
31                 }
32             }
33         });
34
35         services.execute(new Runnable() {
36             @Override
37             public void run() {
38                 try {
39                     String data1 = "edf";
40                     System.out.println("线程" + Thread.currentThread().getName() + "正准备把数据" + data1 + "换出去");
41                     Thread.sleep((long) (Math.random() * 10000));
42                     // 进行数据的交换
43                     String data2 = (String) exchanger.exchange(data1);
44                     System.out.println("线程" + Thread.currentThread().getName() + "换回的数据是" + data2);
45                 } catch (InterruptedException e) {
46                     // TODO Auto-generated catch block
47                     e.printStackTrace();
48                 }
49             }
50         });
51         services.shutdown();
52     }
53 }

原文地址:https://www.cnblogs.com/ssh-html/p/11048536.html

时间: 2024-10-06 00:16:44

Java中的线程--线程中的工具的相关文章

Java(多)线程中注入Spring的Bean

问题说明 今天在web应用中用到了Java多线程的技术来并发处理一些业务,但在执行时一直会报NullPointerException的错误,问题定位了一下发现是线程中的Spring bean没有被注入,bean对象的值为null. 原因分析 web容器在启动应用时,并没有提前将线程中的bean注入(在线程启动前,web容易也是无法感知的) 解决方案 方法有多种,网上也看到了不少. 1. 使用static声明变量 可参见 引用 http://blog.csdn.net/bjamosgavin/ar

Java中事件分发线程(EDT)与SwingUtilities.invokeLater相关总结

前言:这篇文章严格来说不算原创,算是我对这方面知识的一点小结,素材来至其他网友.当然我在我写的C段查询工具也用到了这方面的东西,不过由于代码太多不方便用作事例,因此用了他人的素材总结一下,望理解O(∩_∩)O~ 一 Swing线程基础 一个Swing程序中一般有下面三种类型的线程:    * 初始化线程(Initial Thread)    * UI事件调度线程(EDT)    * 任务线程(Worker Thread)每个程序必须有一个main方法,这是程序的入口.该方法运行在初始化或启动线程

Java中的守护线程

Java中的守护线程 Java中的守护线程与UNIX中的守护线程概念不同,UNIX中的守护线程相当于一项服务,一直运行在后台,而Java中的守护线程是这样定义的: A daemon thread is a thread, that does not prevent the JVM from exiting when the program finishes but the thread is still running. 也就是说,当程序中只有守护线程时,JVM就会自动退出,典型的守护线程就是垃

JAVA线程池中队列与池大小的关系

JAVA线程中对于线程池(ThreadPoolExecutor)中队列,池大小,核心线程的关系写出自己的理解: 1:核心线程:简单来讲就是线程池中能否允许同时并发运行的线程的数量 2:线程池大小:线程池中最多能够容纳的线程的数量. 3:队列:对提交过来的任务的处理模式. 对于线程池与队列的交互有个原则: 如果队列发过来的任务,发现线程池中正在运行的线程的数量小于核心线程,则立即创建新的线程,无需进入队列等待.如果正在运行的线程等于或者大于核心线程,则必须参考提交的任务能否加入队列中去. 1:提交

Java线程池中线程的状态简介

首先明确一下线程在JVM中的各个状态(JavaCore文件中) 1.死锁,Deadlock(重点关注) 2.执行中,Runnable(重点关注) 3.等待资源,Waiting on condition(重点关注) 4.等待监控器检查资源,Waiting on monitor(eg:如果使用System.out.println等需要分配计算机资源的时候线程会如此等待,主要还需看堆栈) 5.暂停,Suspended 6.对象等待中,Object.wait() 7.阻塞,Blocked(重点关注) 8

线程基础:线程(3)——JAVA中的基本线程操作(中)

(接上文<线程基础:线程(2)--JAVA中的基本线程操作(上)>) 1-4.注意synchronized关键字的使用 在前面的文章中我们主要讲解的是线程中"对象锁"的工作原理和操作方式.在讲解synchronized关键字的时候,我们还提到了synchronized关键字可以标注的位置.大家经常看到相当部分的网贴,在它们的代码示例中将synchronized关键字加载到代码的方法体上,然后告诉读者:这个操作是线程安全的.代码可能如下: /** * 这个类的class对象进

Java线程安全性中的对象发布和逸出

发布(Publish)和逸出(Escape)这两个概念倒是第一次听说,不过它在实际当中却十分常见,这和Java并发编程的线程安全性就很大的关系. 什么是发布?简单来说就是提供一个对象的引用给作用域之外的代码.比如return一个对象,或者作为参数传递到其他类的方法中. 什么是逸出?如果一个类还没有构造结束就已经提供给了外部代码一个对象引用即发布了该对象,此时叫做对象逸出,对象的逸出会破坏线程的安全性. 概念我们知道了,可我们要关注什么地方呢?我们要关注的时候就是逸出问题,在不该发布该对象的地方就

JAVA学习篇--ThreadLocal,Java中特殊的线程绑定机制

在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个connection连接).那么ThreadLocal是如果做到的呢?它和同步锁的不同在哪里? 是什么: 对于ThreadLocal看英文单词我们很容易理解为一个线程的本地实现,但是它并不是一个Thread,而是threadlocalvariable(线程局部变量).也许把它命名为ThreadLoc

java中等待所有线程都执行结束

转自:http://blog.csdn.net/liweisnake/article/details/12966761 今天看到一篇文章,是关于java中如何等待所有线程都执行结束,文章总结得很好,原文如下http://software.intel.com/zh-cn/blogs/2013/10/15/java-countdownlatchcyclicbarrier/?utm_campaign=CSDN&utm_source=intel.csdn.net&utm_medium=Link&a

Java中的守护线程和非守护线程(转载)

<什么是守护线程,什么是非守护线程> Java有两种Thread:“守护线程Daemon”(守护线程)与“用户线程User”(非守护线程). 用户线程:非守护线程包括常规的用户线程或诸如用于处理GUI事件的事件调度线程,Java虚拟机在它所有非守护线程已经离开后自动离开. 守护线程:守护线程则是用来服务用户线程的,比如说GC线程.如果没有其他用户线程在运行,那么就没有可服务对象,也就没有理由继续下去.(操作系统里面是没有所谓的守护线程的概念,只有守护进程一说,但是Java语言机制是构建在JVM