java并发编程_基本模块构建
读《java并发编程实战》第五章学习记录:该章节主要介绍一些并发编程中一些基本的构建模块。如并发容器和并发工具类(闭锁和栅栏)以及一些需要注意的情况
并发容器
1. ConcurrentHashMap :
对HashMap的散列表进行分段加锁,从而实现较高的并发访问需求,但实现并发需求的同时,像一些需要迭代全集合的方法如果 size()返回的值可能就不是非常准确的,这是它的缺点 .大多数并发情况下应该采用ConcurrentHashMap,但一些对原子性要求较高的操作,如程序需要对整个map进行独占式访问的时候,采用Collections.synchronziedMap 这个集合
2. CopyOnWriteArrayList :
从名字上就可以看出,在写的时候拷贝列表。应用场景:当迭代操作占主导,更新操作较少的情况下使用该容器比较好
同步工具类
1. 闭锁(CountDownLatch): 根据jdk给的示例代码,主要有两种应用场景: a,工作线程需要同时启动,先完成工作的线程需要等待至所有线程完成任务方可执行下一步操作,如下Driver示例:b,将任务分成相同的N份,待所有的部分都完成后,再执行后续操作,如Driver2所示:
class Driver { // ...
void main() throws InterruptedException {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N); for (int i = 0; i < N; ++i) // create and start threads
new Thread(new Worker(startSignal, doneSignal)).start(); doSomethingElse(); // don't let run yet
startSignal.countDown(); // let all threads proceed
doSomethingElse();
doneSignal.await(); // wait for all to finish
}
} class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run() {
try {
startSignal.await(); //初始化后的线程们在闭锁上阻塞,当主线程调用startSignal.countDown()时,所有线程开始运行
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {} // return; } void doWork() { ... }
}
class Driver2 { // ...
void main() throws InterruptedException {
CountDownLatch doneSignal = new CountDownLatch(N);
Executor e = ... for (int i = 0; i < N; ++i) // create and start threads
e.execute(new WorkerRunnable(doneSignal, i)); //任务放入线程池 doneSignal.await(); // wait for all to finish
}
} class WorkerRunnable implements Runnable {
private final CountDownLatch doneSignal;
private final int i;
WorkerRunnable(CountDownLatch doneSignal, int i) {
this.doneSignal = doneSignal;
this.i = i;
}
public void run() {
try {
doWork(i);
doneSignal.countDown(); //
} catch (InterruptedException ex) {} // return;
} void doWork() { ... }
}
2. 栅栏(CyclicBarrier):其实栅栏的作用和闭锁的第二种应用场景很相似,都是将一个大任务分解成多个相同的小任务执行,每个小任务对应一个工作线程。它们的区别在于栅栏是可以重复使用的,而闭锁是一次性的。(引用api中的解释:latch is a one-shot phenomenon -- the count cannot be reset. If you need a version that resets the count, consider using a CyclicBarrier ; The barrier is called cyclic because it can be re-used after the waiting threads are released. )所以说,栅栏适用于小任务需要重复执行的情况。下面引用jdk的示例代码:
class Solver {
final int N;
final float[][] data;
final CyclicBarrier barrier; class Worker implements Runnable {
int myRow;
Worker(int row) { myRow = row; }
public void run() {
while (!done()) {
processRow(myRow); //处理所有行的大任务分解成多个处理一行的小任务,每个相同的小任务对应一个工作线程 try {
barrier.await(); //每个线程处理完分配给自己的小任务后,阻塞等待。直到所有的线程都完成任务,才release
} catch (InterruptedException ex) {
return;
} catch (BrokenBarrierException ex) {
return;
}
}
}
} public Solver(float[][] matrix) {
data = matrix;
N = matrix.length;
barrier = new CyclicBarrier(N,
new Runnable() { //当所有的工作线程都release的时候,执行该Runnable对象,进行一些“收尾”工作,如下面的合并行
public void run() {
mergeRows(...);
}
});
for (int i = 0; i < N; ++i)
new Thread(new Worker(i)).start(); //为每一行分配一个工作线程 waitUntilDone();
}
}
3.信号量(Semaphore):用来限定资源的可访问线程数量,线程访问资源需要先获得许可;
4.FutureTask:代表一个开销较大的异步任务
5. 阻塞队列(BlockQueue):适用于 “生产者和消费者”的应用场景。参照书上给的例子,写了一个demo:生产者读取文件到阻塞队列,消费者从队列中取出文件并打印文件名
/**
*生产者线程,负责将文件放入阻塞队列
*/
public class Producer implements Runnable{
private File root;
private BlockingQueue<File> queue;
public Producer(File root, BlockingQueue<File> queue) {
super();
this.root = root;
this.queue = queue;
}
@Override
public void run() {
try {
putFilesIntoQueue(root);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @param root
* @throws InterruptedException
* 以给定文件为跟将root下的所有文件名都放入阻塞队列中
*/
private void putFilesIntoQueue(File root) throws InterruptedException {
File[] subFiles = root.listFiles();
for(File file: subFiles){
if(file.isFile()){
queue.put(file);
}else{
putFilesIntoQueue(file);
}
}
} }
/**
*消费者线程,负责将文件从阻塞队列中取出
*/
public class Consumer implements Runnable{
private BlockingQueue<File> queue;
public Consumer(BlockingQueue<File> queue) {
super();
this.queue = queue;
}
@Override
public void run() {
try {
getOutFromQueue();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @param root
* @throws InterruptedException
* 从阻塞队列中取出文件并打印出文件名
*/
private void getOutFromQueue() throws InterruptedException {
while(true){
String name=queue.take().getName();
System.out.println(Thread.currentThread().getName()+": "+name);
}
} }
/**
*测试客户端
*/
public class Main {
public static void main(String[] args) {
File[] roots={
new File("C://"),new File("D://"),
new File("E://"),new File("F://")
};
BlockingQueue<File> queue=new ArrayBlockingQueue<>(20);
//定义一组生产者线程,每个线程对应一个盘符
for(int i=0;i<4;i++){
new Thread(new Producer(roots[i],queue)).start();
}
//定义一组消费者线程
for(int i=0;i<10;i++){
new Thread(new Consumer(queue)).start();
}
}
}
其他
1. 关于中断和阻塞:对于调用可能抛出InterruptException的方法,如sleep(),await()方法时应该如下处理:
1.1 重新抛出该异常
1.2 对于不能重新抛出异常的情况:如下所示,采取Thread.currentThread.interrupt()的方法恢复中断
new Runnable() {
public void run() {
try{
doSomeThing()
}catch(InterruptedException e){
Thread.currentThread.interrupt();
}
为啥这样处理? 看到时,再补充。。
java并发编程_基本模块构建的更多相关文章
- java并发编程_建立概念
在学习多线程编程时,相信大家会遇到好多概念类的东西,对于这些概念的不准确理解会导致后面越学越糊涂,现将学习过程中遇到的概念整理到这篇博客上,一来记录学习点滴,二来也加深理解,如果有理解不准确的地方,希 ...
- JAVA并发编程学习笔记------基础构建模块
一.并发容器:ConcurrentHashMap:1.分段锁机制: 任意数量的读取线程可以并发的访问map,执行读取操作的线程和执行写入操作的线程可以并发的访问Map,并且一定数量的写入线程可以并发的 ...
- java并发编程(7)构建自定义同步工具及条件队列
构建自定义同步工具 一.通过轮询与休眠的方式实现简单的有界缓存 public void put(V v) throws InterruptedException { while (true) { // ...
- java并发编程实战学习(3)--基础构建模块
转自:java并发编程实战 5.3阻塞队列和生产者-消费者模式 BlockingQueue阻塞队列提供可阻塞的put和take方法,以及支持定时的offer和poll方法.如果队列已经满了,那么put ...
- 《Java并发编程实战》/童云兰译【PDF】下载
<Java并发编程实战>/童云兰译[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062521 内容简介 本书深入浅出地介绍了Jav ...
- 《java并发编程实战》笔记
<java并发编程实战>这本书配合并发编程网中的并发系列文章一起看,效果会好很多. 并发系列的文章链接为: Java并发性和多线程介绍目录 建议: <java并发编程实战>第 ...
- java并发编程之美-阅读记录11
java并发编程实践 11.1ArrayBlockingQueue的使用 有关logback异步日志打印中的ArrayBlockingQueue的使用 1.异步日志打印模型概述 在高并发.高流量并且响 ...
- Java并发编程实战——读后感
未完待续. 阅读帮助 本文运用<如何阅读一本书>的学习方法进行学习. P15 表示对于书的第15页. Java并发编程实战简称为并发书或者该书之类的. 熟能生巧,不断地去理解,就像欣赏一部 ...
- 【java并发编程实战】-----线程基本概念
学习Java并发已经有一个多月了,感觉有些东西学习一会儿了就会忘记,做了一些笔记但是不系统,对于Java并发这么大的"系统",需要自己好好总结.整理才能征服它.希望同仁们一起来学习 ...
随机推荐
- 转:为什么需要htons(), ntohl(), ntohs(),htons() 函数
为什么需要htons(), ntohl(), ntohs(),htons() 函数: 在C/C++写网络程序的时候,往往会遇到字节的网络顺序和主机顺序的问题.这是就可能用到htons(), ntohl ...
- 仿QQ5.0以上新版本侧滑效果
1.此效果使用了csdn大神孙国威的代码案例在此感谢附上参考博客地址: http://blog.csdn.net/manoel/article/details/39013095/#plain 2.sl ...
- nodejs 记入
1. vs2015 使用最新的 nodejs refer : http://josharepoint.com/2016/05/04/how-to-configure-visual-studio-201 ...
- Qt源码分析之信号和槽机制
Qt的信号和槽机制是Qt的一大特点,实际上这是和MFC中的消息映射机制相似的东西,要完成的事情也差不多,就是发送一个消息然后让其它窗口响应,当然,这里的消息是广义的说法,简单点说就是如何在一个类的一个 ...
- easyUI treeGrid 的小例子
今天由于业务的需要,于是采用了easyui的的treeGrid控件. <table title="Folder Browser" class="easyui-tre ...
- HDOJ(HDU) 1570 A C
Problem Description Are you excited when you see the title "AC" ? If the answer is YES , A ...
- Android调用第三方应用
Intent intent=new Intent(); //包名 包名+类名(全路径) intent.setClassName("com.qn.app.store", " ...
- go语言的安装和配置,以及包引用
1.下载和安装 首先大家可以去官网下载 http://golang.org/dl/ 如果官网你看不懂的话,可以到这里下载: http://golangtc.com/download ,这里也提供了百度 ...
- ORCL_UNINSTALL_WIN10
1.开始->设置->控制面板->管理工具->服务 停止所有Oracle服务. 2.运行Universal Installer 3.选择卸载产品 4.只勾选Oracle Data ...
- SQL Server 系统时间
getdate()函数:取得系统当前的日期和时间.返回值为datetime类型的. 用法:getdate() 例子: select getdate() as dte,dateadd(day,-1,ge ...