Java并发编程(十一)常用工具
Java为开发提供了很多有用的工具类,这些工具类可以帮助我们更加高效的编写并发程序,本篇我们将介绍这些实用工具的用法。
ThreadLocal
ThreadLocal类用于解决多线程共享一个变量的问题,当多线程访问同一个变量时可能会导致结果的错误,防止这种错误第一种办法就是使用锁来保护对象;第二种方法就是彻底根除共享,即每个线程访问自己私有的变量。有的同学会觉得第二种方法就会有一些局限性,因为有些时候不得不共享同一个变量。是的确实有局限性,但是在很多情况下是可以不共享变量就能达到同样的效果,ThreadLocal就是为了解决这一问题而设计的。
ThreadLocal使用方法如下:
class IncreaseThread implements Runnable {
    public void run() {
        for(int i=0; i< 10000; i++) {
            TLTest.number.set(TLTest.number.get() + 1);
        }
        //以下为汇总代码
        synchronized(TLTest.result) {
            TLTest.result += TLTest.number.get();
        }
    }
}
public class TLTest {
    public static ThreadLocal<Integer> number;
    public static Integer result = 0;
    public static void main(String[] args) throws Exception {
        number = new ThreadLocal<Integer>() {
            public Integer initialValue() {
                return 0;
            }
        };
        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(new IncreaseThread());
        exec.execute(new IncreaseThread());
        exec.shutdown();
        Thread.sleep(500);
        System.out.println("result: " + result);
    }
}
输出结果如下:
result: 20000
在TLTest类中我们定义了ThreadLocal变量和Integer变量,ThreadLocal变量需要为其创建一个匿名内部类来实现为其指定初始值,我们将初始值指定为0。我们定义了一个线程类,这个线程负责将ThreadLocal的值加10000,最后线程会将自己的计算结果汇总到TLTest.result变量中。这个过程中虽然我们创建的两个线程都对同一个ThreadLocal变量进行操作,但是没有导致计算结果出错。因为ThreadLocal为每一个线程分配了不同的存储空间,我们可以简单的将其理解为一个线程对象和值的Map<Thread,Integer>(注意:只是可以这么理解,但实际上不是)。
CountDownLatch
CountDownLatch用于线程间的合作,其使用方法和wait()/notify()类似,CountDownLatch类有两个方法:countDown()和await()方法,在创建CountDownLatch的对象时为其指定countDown()方法调用的次数,当调用await()方法时当前线程会一直被阻塞,直到countDown()方法被调用了指定的次数。设想一种情况,一个工头在接到任务时会把任务分发给不同的工人,只有当所有的工人都完成自己的工作的时候,工头才可以交工。
我们用代码模拟一下这种情况:
class Worker implements Runnable {
    private int id;
    public Worker(int id) {
                this.id = id;
    }
    public void run() {
        Random rand = new Random();
        int workTime = rand.nextInt(1000);
        System.out.println(id + ": 开始干活");
        try { Thread.sleep(workTime); } catch (Exception e) {}
        System.out.println(id + ": 完成了");
        CDLTest.cdl.countDown();
    }
}
public class CDLTest {
    private static int numberOfWorker = 3;
    public static CountDownLatch cdl = new CountDownLatch(numberOfWorker);
    public static void main(String[] args) throws Exception {
        ExecutorService exec = Executors.newCachedThreadPool();
        for(int i=0; i<numberOfWorker; i++) {
            exec.execute(new Worker(i));
        }
        exec.shutdown();
        cdl.await();
        System.out.println("工头:交工");
    }
}
输出结果如下:
1: 开始干活
2: 开始干活
0: 开始干活
1: 完成了
2: 完成了
0: 完成了
工头:交工
在本例中主线程承担工头的角色,调用await()方法等待工人线程完成工作。我们还通过线程池创建了3个工人线程,我们使用随机数让每个线程随机睡眠0-1000毫秒,用来模拟工人工作。
每个工人完成自己的任务后调用countDown()方法,当所有的工人线程都做完自己的工作后主线程就可以“交工”了。
PriorityBlockingQueue
PriorityBlockingQueue和前面讲过的LinkedBlockingQueue、ArrayBlockingQueue相似,他们都实现了BlockingQueue接口,但是PriorityBlockingQueue和它们最大的区别是这个队列每次取出的都是“优先级”最高的,而不是最先进入的。因此要想实现它的优先级的特性,容器中的元素必须实现了Comparable接口,否则容器将抛ClassCastException异常。此外PriorityBlockingQueue也是线程安全的,因此使用的时候不用加锁。由于之前我们测试过LinkedBlockingQueue的阻塞性,因此PriorityBlockingQueue的阻塞性我们就不测试了,简单的测试一下它的“优先级”的性质:
public class PBQTest {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> pbq = new PriorityBlockingQueue<String>();
        String[] strs = new String[]{"C", "A", "B"};
        for(int i=0;i <strs.length;i++) {
            pbq.add(strs[i]);
        }
        while(!pbq.isEmpty()) {
            System.out.println(pbq.take());
        }
    }
}
输出结果如下:
A
B
C
String类实现了Comparable接口,根据字母顺序比较字符串的大小。我们向队列中添加元素的顺序是"C", "A", "B",而取出顺序是"A", "B", "C",此因可以看出其“优先级”的性质。
总结
本篇介绍了三个常用的工具类,ThreadLocal用于解决多线程共享同一个变量的问题,它相当于创建了一个以线程对象为key以目标对象为value的一个Map,但实际上和Map是有区别的,比如Map对象不会在某个线程退出后对相应的value做垃圾回收,而ThreadLocal会对其进行回收。CountDownLatch用于同步多个任务,让某些任务等待其它任务执行的一组操作,需要注意的是可以有多个线程调用await()方法,当调用countDown()的次数到达指定数量的时候所有调用await()方法的线程都会从阻塞状态变为运行状态。PriorityBlockingQueue的用法和其它实现BlockingQueue接口的用法相似,只是PriorityBlockingQueue中的元素的取出顺序是按照优先级排序的。
公众号:今日说码。关注我的公众号,可查看连载文章。遇到不理解的问题,直接在公众号留言即可。
Java并发编程(十一)常用工具的更多相关文章
- 【漫画】JAVA并发编程之并发模拟工具
		
原创声明:本文来源于公众号[胖滚猪学编程],转载请注明出处. 上一节[漫画]JAVA并发编程三大Bug源头(可见性.原子性.有序性)我们聊了聊并发编程的三个bug源头,这还没开始进入并发世界,胖滚猪就 ...
 - java并发编程[持续更新]
		
目录 java并发编程 1.常用类介绍 Semaphore 2.名词解释 2.1 线程安全 2.2 可重入锁和不可重入锁 java并发编程 1.常用类介绍 Semaphore Semaphore 类是 ...
 - java并发编程笔记(十一)——高并发处理思路和手段
		
java并发编程笔记(十一)--高并发处理思路和手段 扩容 垂直扩容(纵向扩展):提高系统部件能力 水平扩容(横向扩容):增加更多系统成员来实现 缓存 缓存特征 命中率:命中数/(命中数+没有命中数) ...
 - java并发编程工具类JUC第八篇:ConcurrentHashMap
		
在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...
 - Java并发编程原理与实战三十一:Future&FutureTask 浅析
		
一.Futrue模式有什么用?------>正所谓技术来源与生活,这里举个栗子.在家里,我们都有煮菜的经验.(如果没有的话,你们还怎样来泡女朋友呢?你懂得).现在女票要你煮四菜一汤,这汤是鸡汤, ...
 - Java并发编程系列-(2) 线程的并发工具类
		
2.线程的并发工具类 2.1 Fork-Join JDK 7中引入了fork-join框架,专门来解决计算密集型的任务.可以将一个大任务,拆分成若干个小任务,如下图所示: Fork-Join框架利用了 ...
 - java并发编程笔记(二)——并发工具
		
java并发编程笔记(二)--并发工具 工具: Postman:http请求模拟工具 Apache Bench(AB):Apache附带的工具,测试网站性能 JMeter:Apache组织开发的压力测 ...
 - java并发编程系列原理篇--JDK中的通信工具类Semaphore
		
前言 java多线程之间进行通信时,JDK主要提供了以下几种通信工具类.主要有Semaphore.CountDownLatch.CyclicBarrier.exchanger.Phaser这几个通讯类 ...
 - java并发编程工具类JUC第四篇:LinkedBlockingQueue链表队列
		
在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue. LinkedBlockingQueue 队列是Blo ...
 - java并发编程工具类JUC第七篇:BlockingDeque双端阻塞队列
		
在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...
 
随机推荐
- 5 使用ip代理池爬取糗事百科
			
从09年读本科开始学计算机以来,一直在迷茫中度过,很想学些东西,做些事情,却往往陷进一些技术细节而蹉跎时光.直到最近几个月,才明白程序员的意义并不是要搞清楚所有代码细节,而是要有更宏高的方向,要有更专 ...
 - sqldataAdapter/dataset/datatable的使用
			
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Loa ...
 - 有关从经典部署模型迁移到 Azure Resource Manager 部署模型的常见问题
			
此迁移计划是否影响 Azure 虚拟机上运行的任何现有服务或应用程序? 不可以. VM(经典)是公开上市的完全受支持的服务. 你可以继续使用这些资源来拓展你在 Azure 上的足迹. 如果我近期不打算 ...
 - 【Oracle】锁表处理 SQL 错误: ORA-00054: 资源正忙, 但指定以 NOWAIT 方式获取资源, 或者超时失效
			
问题描述有时候ORACLE数据的某些表由于频繁操作,而且比较大,会导致锁表(死锁). 问题分析(1)锁的分析ORACLE里锁有以下几种模式:0:none1:null 空2:Row-S 行共享(RS): ...
 - asp.net生成PDF文件参考 .
			
TextSharp 是用来生成 PDF 的一个组件,在 1998 年夏天的时候,Bruno Lowagie ,iText 的创作者,参与了学校的一个项目,当时使用 HTML 来生成报告,但是,使用 ...
 - Linux下的Mysql的远程访问
			
mysql的服务端[192.168.25.136] 1,在远程访问之前需先配置防火墙 service iptables stop (不推荐,可配置开通3306端口) 2,授权 mysql> gr ...
 - iOS模拟器命令xcrun simctl系列(自动化测试)
			
1. 列出安装的可用的模拟器: xcrun instruments -s [如:iPhone 5s (9.0) [00AB3BB6-C5DC-45C7-804F-6B88F57C2AFF] (Simu ...
 - apt 安装 tomcat
			
apt 安装 tomcat 直接使用 agt-get 安装 apt-get install tomcat7 # or apt-get install tomcat8 需要一段时间后就安装完成了. 安装 ...
 - 使用Hash直接登录Windows(HASH传递)
			
抓取windows hash值 得到administrator的hash: 598DDCE2660D3193AAD3B435B51404EE:2D20D252A479F485CDF5E171D9398 ...
 - linux服务器安全配置10大技巧
			
1.禁止ping/etc/rc.d/rc.localecho 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all2.对用户和口令文件进行权限控制chmod 6 ...