newFixedThreadPool
创建一个固定大小的线程池。
shutdown():用于关闭启动线程,如果不调用该语句,jvm不会关闭。
awaitTermination():用于等待子线程结束,再继续执行下面的代码。该例中我设置一直等着子线程结束。 Java代码 收藏代码
public class Test { public static void main(String[] args) throws IOException, InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(2);
for (int i = 0; i < 4; i++) {
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("thread start");
}
};
service.execute(run);
}
service.shutdown();
service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
System.out.println("all thread complete");
}
} 输出:
thread start
thread start
thread start
thread start
all thread complete
newScheduledThreadPool
这个先不说,我喜欢用spring quartz.
CyclicBarrier
假设有只有的一个场景:每个线程代表一个跑步运动员,当运动员都准备好后,才一起出发,只要有一个人没有准备好,大家都等待. Java代码 收藏代码
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; class Runner implements Runnable { private CyclicBarrier barrier; private String name; public Runner(CyclicBarrier barrier, String name) {
super();
this.barrier = barrier;
this.name = name;
} @Override
public void run() {
try {
Thread.sleep(1000 * (new Random()).nextInt(8));
System.out.println(name + " 准备OK.");
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(name + " Go!!");
}
} public class Race { public static void main(String[] args) throws IOException, InterruptedException {
CyclicBarrier barrier = new CyclicBarrier(3); ExecutorService executor = Executors.newFixedThreadPool(3);
executor.submit(new Thread(new Runner(barrier, "zhangsan")));
executor.submit(new Thread(new Runner(barrier, "lisi")));
executor.submit(new Thread(new Runner(barrier, "wangwu"))); executor.shutdown();
} } 输出:
wangwu 准备OK.
zhangsan 准备OK.
lisi 准备OK.
lisi Go!!
zhangsan Go!!
wangwu Go!!
ThreadPoolExecutor newFixedThreadPool生成一个固定的线程池,顾名思义,线程池的线程是不会释放的,即使它是Idle。这就会产生性能问题,比如如果线程池的大小为200,当全部使用完毕后,所有的线程会继续留在池中,相应的内存和线程切换(while(true)+sleep循环)都会增加。如果要避免这个问题,就必须直接使用ThreadPoolExecutor()来构造。可以像Tomcat的线程池一样设置“最大线程数”、“最小线程数”和“空闲线程keepAlive的时间”。 ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) corePoolSize:池中所保存的线程数,包括空闲线程(非最大同时干活的线程数)。如果池中线程数多于 corePoolSize,则这些多出的线程在空闲时间超过 keepAliveTime 时将会终止。
maximumPoolSize:线程池中最大线程数
keepAliveTime:线程空闲回收的时间
unit:keepAliveTime的单位
workQueue:保存任务的队列,可以如下选择: 无界队列: new LinkedBlockingQueue<Runnable>();
有界队列: new ArrayBlockingQueue<Runnable>(8);你不想让客户端无限的请求吃光你的CPU和内存吧,那就用有界队列
handler:当提交任务数大于队列size会抛出RejectedExecutionException,可选的值为: ThreadPoolExecutor.CallerRunsPolicy 等待队列空闲
ThreadPoolExecutor.DiscardPolicy:丢弃要插入队列的任务
ThreadPoolExecutor.DiscardOldestPolicy:删除队头的任务
关于corePoolSize和maximumPoolSize: Java官方Docs写道:
当新任务在方法 execute(java.lang.Runnable) 中提交时,如果运行的线程少于 corePoolSize,则创建新线程来处理请求(即使存在空闲线程)。如果运行的线程多于 corePoolSize 而少于 maximumPoolSize,则仅当队列(queue)满时才创建新线程。如果设置的 corePoolSize 和 maximumPoolSize 相同,则创建了固定大小的线程池。如果将 maximumPoolSize 设置为基本的无界值(如 Integer.MAX_VALUE),则允许池适应任意数量的并发任务。 Java代码 收藏代码
public class Test { public static void main(String[] args) {
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 1, TimeUnit.DAYS, queue); for (int i = 0; i < 20; i++) {
final int index = i;
executor.execute(new Runnable() {
public void run() {
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(String.format("thread %d finished", index));
}
});
}
executor.shutdown();
}
} 原子变量(Atomic )
并发库中的BlockingQueue是一个比较好玩的类,顾名思义,就是阻塞队列。该类主要提供了两个方法put()和take(),前者将一个对象放到队列中,如果队列已经满了,就等待直到有空闲节点;后者从head取一个对象,如果没有对象,就等待直到有可取的对象。 下面的例子比较简单,一个读线程,用于将要处理的文件对象添加到阻塞队列中,另外四个写线程用于取出文件对象,为了模拟写操作耗时长的特点,特让线程睡眠一段随机长度的时间。另外,该Demo也使用到了线程池和原子整型(AtomicInteger),AtomicInteger可以在并发情况下达到原子化更新,避免使用了synchronized,而且性能非常高。由于阻塞队列的put和take操作会阻塞,为了使线程退出,在队列中添加了一个“标识”,算法中也叫“哨兵”,当发现这个哨兵后,写线程就退出。 Java代码 收藏代码
import java.io.File;
import java.io.FileFilter;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger; public class Test { static long randomTime() {
return (long) (Math.random() * 1000);
} public static void main(String[] args) {
// 能容纳100个文件
final BlockingQueue<File> queue = new LinkedBlockingQueue<File>(100);
// 线程池
final ExecutorService exec = Executors.newFixedThreadPool(5);
final File root = new File("D:\\dist\\blank");
// 完成标志
final File exitFile = new File("");
// 读个数
final AtomicInteger rc = new AtomicInteger();
// 写个数
final AtomicInteger wc = new AtomicInteger();
// 读线程
Runnable read = new Runnable() {
public void run() {
scanFile(root);
scanFile(exitFile);
} public void scanFile(File file) {
if (file.isDirectory()) {
File[] files = file.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.isDirectory() || pathname.getPath().endsWith(".log");
}
});
for (File one : files)
scanFile(one);
} else {
try {
int index = rc.incrementAndGet();
System.out.println("Read0: " + index + " " + file.getPath());
queue.put(file);
} catch (InterruptedException e) {
}
}
}
};
exec.submit(read);
// 四个写线程
for (int index = 0; index < 4; index++) {
// write thread
final int num = index;
Runnable write = new Runnable() {
String threadName = "Write" + num; public void run() {
while (true) {
try {
Thread.sleep(randomTime());
int index = wc.incrementAndGet();
File file = queue.take();
// 队列已经无对象
if (file == exitFile) {
// 再次添加"标志",以让其他线程正常退出
queue.put(exitFile);
break;
}
System.out.println(threadName + ": " + index + " " + file.getPath());
} catch (InterruptedException e) {
}
}
} };
exec.submit(write);
}
exec.shutdown();
} } CountDownLatch 从名字可以看出,CountDownLatch是一个倒数计数的锁,当倒数到0时触发事件,也就是开锁,其他人就可以进入了。在一些应用场合中,需要等待某个条件达到要求后才能做后面的事情;同时当线程都完成后也会触发事件,以便进行后面的操作。
CountDownLatch最重要的方法是countDown()和await(),前者主要是倒数一次,后者是等待倒数到0,如果没有到达0,就只有阻塞等待了。
一个CountDouwnLatch实例是不能重复使用的,也就是说它是一次性的,锁一经被打开就不能再关闭使用了,如果想重复使用,请考虑使用CyclicBarrier。
下面的例子简单的说明了CountDownLatch的使用方法,模拟了100米赛跑,10名选手已经准备就绪,只等裁判一声令下。当所有人都到达终点时,比赛结束。 Java代码 收藏代码
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Test { public static void main(String[] args) throws InterruptedException { // 开始的倒数锁
final CountDownLatch begin = new CountDownLatch(1); // 结束的倒数锁
final CountDownLatch end = new CountDownLatch(10); // 十名选手
final ExecutorService exec = Executors.newFixedThreadPool(10); for (int index = 0; index < 10; index++) {
final int NO = index + 1;
Runnable run = new Runnable() {
public void run() {
try {
begin.await();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("No." + NO + " arrived");
} catch (InterruptedException e) {
} finally {
end.countDown();
}
}
};
exec.submit(run);
}
System.out.println("Game Start");
begin.countDown();
end.await();
System.out.println("Game Over");
exec.shutdown();
} } 使用Callable和Future实现线程等待和多线程返回值 假设在main线程启动一个线程,然后main线程需要等待子线程结束后,再继续下面的操作,我们会通过join方法阻塞main线程,代码如下: Java代码 收藏代码
Runnable runnable = ...;
Thread t = new Thread(runnable);
t.start();
t.join();
......
通过JDK1.5线程池管理的线程可以使用Callable和Future实现(join()方法无法应用到在线程池线程) Java代码 收藏代码
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class Test { public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("start main thread");
final ExecutorService exec = Executors.newFixedThreadPool(5); Callable<String> call = new Callable<String>() {
public String call() throws Exception {
System.out.println(" start new thread.");
Thread.sleep(1000 * 5);
System.out.println(" end new thread.");
return "some value.";
}
};
Future<String> task = exec.submit(call);
Thread.sleep(1000 * 2);
task.get(); // 阻塞,并待子线程结束,
exec.shutdown();
exec.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
System.out.println("end main thread");
} } Java代码 收藏代码
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; /**
* 多线程返回值测试
*/
public class ThreadTest { public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("start main thread");
int threadCount = 5;
final ExecutorService exec = Executors.newFixedThreadPool(threadCount); List<Future<Integer>> tasks = new ArrayList<Future<Integer>>();
for (int i = 0; i < threadCount; i++) {
Callable<Integer> call = new Callable<Integer>() {
public Integer call() throws Exception {
Thread.sleep(1000);
return 1;
}
};
tasks.add(exec.submit(call));
}
long total = 0;
for (Future<Integer> future : tasks) {
total += future.get();
}
exec.shutdown();
System.out.println("total: " + total);
System.out.println("end main thread");
}
} CompletionService
这个东西的使用上很类似上面的example,不同的是,它会首先取完成任务的线程。下面的参考文章里,专门提到这个,大家有兴趣可以看下,例子: Java代码 收藏代码
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class Test {
public static void main(String[] args) throws InterruptedException,
ExecutionException {
ExecutorService exec = Executors.newFixedThreadPool(10);
CompletionService<String> serv =
new ExecutorCompletionService<String>(exec);
for (int index = 0; index < 5; index++) {
final int NO = index;
Callable<String> downImg = new Callable<String>() {
public String call() throws Exception {
Thread.sleep((long) (Math.random() * 10000));
return "Downloaded Image " + NO;
}
};
serv.submit(downImg);
}
Thread.sleep(1000 * 2);
System.out.println("Show web content");
for (int index = 0; index < 5; index++) {
Future<String> task = serv.take();
String img = task.get();
System.out.println(img);
}
System.out.println("End");
// 关闭线程池
exec.shutdown();
}
} Semaphore信号量 拿到信号量的线程可以进入代码,否则就等待。通过acquire()和release()获取和释放访问许可。下面的例子只允许5个线程同时进入执行acquire()和release()之间的代码 Java代码 收藏代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore; public class Test { public static void main(String[] args) {
// 线程池
ExecutorService exec = Executors.newCachedThreadPool();
// 只能5个线程同时访问
final Semaphore semp = new Semaphore(5);
// 模拟20个客户端访问
for (int index = 0; index < 20; index++) {
final int NO = index;
Runnable run = new Runnable() {
public void run() {
try {
// 获取许可
semp.acquire();
System.out.println("Accessing: " + NO);
Thread.sleep((long) (Math.random() * 10000));
// 访问完后,释放
semp.release();
} catch (InterruptedException e) {
}
}
};
exec.execute(run);
}
// 退出线程池
exec.shutdown();
} } 参考:
jdk1.5中的线程池使用简介
http://www.java3z.com/cwbwebhome/article/article2/2875.html
CAS原理
http://www.blogjava.net/syniii/archive/2010/11/18/338387.html?opt=admin
jdk1.5中java.util.concurrent包编写多线程
http://hi.baidu.com/luotoo/blog/item/b895c3c2d650591e0ef47731.html
ExecutorSerive vs CompletionService
http://www.coderanch.com/t/491704/threads/java/ExecutorSerive-vs-CompletionService -- end --

  

java.util.concurrent包API学习笔记的更多相关文章

  1. 《java.util.concurrent 包源码阅读》 结束语

    <java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...

  2. 【并发编程】【JDK源码】JDK的(J.U.C)java.util.concurrent包结构

    本文从JDK源码包中截取出concurrent包的所有类,对该包整体结构进行一个概述. 在JDK1.5之前,Java中要进行并发编程时,通常需要由程序员独立完成代码实现.当然也有一些开源的框架提供了这 ...

  3. java.util.concurrent包

    在JavaSE5中,JUC(java.util.concurrent)包出现了 在java.util.concurrent包及其子包中,有了很多好玩的新东西: 1.执行器的概念和线程池的实现.Exec ...

  4. 《java.util.concurrent 包源码阅读》02 关于java.util.concurrent.atomic包

    Aomic数据类型有四种类型:AomicBoolean, AomicInteger, AomicLong, 和AomicReferrence(针对Object的)以及它们的数组类型, 还有一个特殊的A ...

  5. 《java.util.concurrent 包源码阅读》04 ConcurrentMap

    Java集合框架中的Map类型的数据结构是非线程安全,在多线程环境中使用时需要手动进行线程同步.因此在java.util.concurrent包中提供了一个线程安全版本的Map类型数据结构:Concu ...

  6. 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分

    这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...

  7. 《java.util.concurrent 包源码阅读》17 信号量 Semaphore

    学过操作系统的朋友都知道信号量,在java.util.concurrent包中也有一个关于信号量的实现:Semaphore. 从代码实现的角度来说,信号量与锁很类似,可以看成是一个有限的共享锁,即只能 ...

  8. java.util.concurrent包下集合类的特点与适用场景

    java.util.concurrent包,此包下的集合都不允许添加null元素 序号 接口 类 特性 适用场景 1 Queue.Collection ArrayBlockingQueue 有界.阻塞 ...

  9. 高并发编程基础(java.util.concurrent包常见类基础)

    JDK5中添加了新的java.util.concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的访问都串行化了,这样保证了线程的安全性,所以这种方法 ...

随机推荐

  1. jQuery ID与Class性能对比之一

    最近一直在做网站的优化方面的工作,在实际优化的过程中逐渐发现yahoo的34条只能作为一个大的方向,除此之外还有很多地方值得前端工程师关注的.结合最近的优化体会及实地测试,现发出来一部分供大家批评指正 ...

  2. 【转】AOP知识点

    ref:http://www.diybloghome.com/prology/975.html 一.概念理解 老规矩,还是先看官方解释:AOP(Aspect-Oriented Programming, ...

  3. hadoop架构

    HADOOP中可以分为两个大的模块,存储模块和计算模块.HDFS作为存储模块,JobTracker,TaskTracker构成计算模块.   1.HADOOP的文件是以HDFS格式存储的   HDFS ...

  4. 如何开启MYSQL远程连接权限

    开启MYSQL远程连接权限 //建议设置固定IP mysql> GRANT ALL PRIVILEGES ON *.* TO root@"8.8.8.8" IDENTIFIE ...

  5. 不再用.NET框架

    .NET 平台很棒.真的很棒.直到它不再那么棒.我为什么不再用 .NET?简单来说,它限制了我们选择的能力(对我来说很重要),转移了我们的注意力,使得我们向内认知它的安全性,替代了帮助我们认知外面广阔 ...

  6. Spannable相关方法

    实现文本链接 其中tv是TextView类型的控件.只需写java代码即可实现链接,无需在xml文件中进行其他的设置. SpannableString spanTxt = new SpannableS ...

  7. Laravel 5 基础(二)- 路由、控制器和视图简介

    查看 app/Http/routes.php Route::get('/', 'WelcomeController@index'); @是一个界定符,前面是控制器,后面是动作,表示当用户请求url / ...

  8. Lua 常用的shell命令

    lua作为一种小巧的脚本语言,其函数等动作可以使用shell命令进行运行和调试,以下是几个常用的shell命令.基本格式是  lua [选项参数] [脚本参数] (1)%lua 程序名.lua     ...

  9. 含有自增序列的表中使用truncate与delete的不同结果

    一个含有自增序列的表,使用delete跟truncate之后会有什么不同结果呢? 大概说一下,使用truncate,表中的记录全部被清除,如果向表中插入数据,那么数据的排序是从1开始的. 如果使用的是 ...

  10. MS MQ 消息队列

    一.安装 先在 控制面板—程序和功能—打开或关闭我windows功能.把 msmq全勾起来 如下图: 二.右击-消息对列—属性—服务器安全性,把禁用未经身份验证的RPC调用勾去掉, 三.然后在专用队列 ...