java使用Executor(执行器)管理线程
一.一个实现了Runnable接口的类
class MyThread implements Runnable{
private static int num = 0;
@Override
public void run() {
while(true){
synchronized(MyThread.class){
++num;
try{
Thread.sleep(500);
} catch(Exception e){
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName() + " " + num);
}
}
}
}
1. newCachedThreadPool()方法
CacheThreadPool会为每一个任务创建一个线程。非常常见的情况是,单个的Executor被用来创建和管理系统中的任务。shutdown()方法可以防止新的任务被提交给这个Executor。如果在shutdown()方法之后提交新任务,则会抛出java.util.concurrent.RejectedExecutionException异常。
public class Main{
public static void main(String[] args){
ExecutorService exes = Executors.newCachedThreadPool();
for(int i=0; i<5; ++i)
exes.execute(new MyThread());
exes.shutdown();
}
}
2.FixedThreadPool()方法
FixedThreadPool使用了优先的线程集来执行所提交的任务。有了它,你就可以一次性预先执行代价高的线程分配。也就是说如果设置的最大线程数量是x,而提交的线程数y,那么(y-x)对应的这些线程要等到前x个线程执行完毕才会执行。
下面的例子中,线程6一直不会有机会执行。因为run()方法中是 while(true), 可以将while(true)去掉,前5个线程执行完毕后,才会执行第6个线程。
public class Main{
public static void main(String[] args){
ExecutorService exes = Executors.newFixedThreadPool(5);
for(int i=0; i<6; ++i)
exes.execute(new MyThread());
exes.shutdown();
}
}
3.newSingleThreadExecutor()方法
public class Main{
public static void main(String[] args){
ExecutorService exes = Executors.newSingleThreadExecutor();
for(int i=0; i<5; ++i)
exes.execute(new MyThread());
exes.shutdown();
}
SingleThreadExecutor就像是线程数量为1的FixedThreadPool。这对于你希望在另一个线程中连续运行的事物(长期存活的任务)来说,都是很有用的。如果想SingleThreadExecutor提交了多个任务,那么这些任务将排队,每个任务都会在下一个任务开始之前结束,所有的任务将使用相同的线程。
二.一个实现了Callable<E>接口的类(从任务中产生返回值)
class MyThread implements Callable<String>{
private static int num = 0;
@Override
public String call() throws Exception {
for(int i=0; i<5; ++i){
synchronized(MyThread.class){
++num;
Thread.sleep(200);
System.out.println(Thread.currentThread().getName() + " " + num);
}
}
return Thread.currentThread().getName() + " success!";
}
}
1.ExecutorService.submit()方法
public class Main{
public static void main(String[] args){
ExecutorService exes = Executors.newCachedThreadPool();
ArrayList<Future<String>> rets = new ArrayList<Future<String>>();
for(int i=0; i<5; ++i)
rets.add(exes.submit(new MyThread()));
for(Future<String> fs : rets){
try {
System.out.println(fs.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
submit()会产生Future对象,它用Callable返回结果的特定类型进行了参数化。可以调用Future的isDone()方法来查询Future是否已经完成。调用Future的get()方法来获取最终线程的执行结果。另外,Future的get()方法是一个阻塞方法,直到结果准备就绪。
三.线程的优先级
class MyThread implements Runnable{
private int priority;
public MyThread(){
}
public MyThread(int priority){
this.priority = priority;
}
private static int num = 0;
private volatile double d;
@Override
public void run() {
Thread.currentThread().setPriority(priority);
while(true){
for(int i=0; i<100000; ++i){
d += (Math.PI+Math.E)/(double)i;
if(i%1000 == 0)
Thread.yield();
}
synchronized(MyThread.class){
++num;
try{
Thread.sleep(500);
} catch(Exception e){
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName() + " " + num);
}
}
}
}
public class Main{
public static void main(String[] args){
ExecutorService exes = Executors.newCachedThreadPool();
for(int i=0; i<5; ++i)
exes.execute(new MyThread(Thread.MIN_PRIORITY));
exes.execute(new MyThread(Thread.MAX_PRIORITY));
exes.shutdown();
}
}
volatile变量保证编译器对循环不进行任何的优化,如果不加入这些运算的话,就不会看到设置线程优先级的效果。数学运算是可以中断的,向控制台打印不能被中断。这里预案算时间足够的长,因此线程调度机制才来的及介入,交换任务并关注优先级,是的最高优先级被优先选择。
四.后台线程
class SimpleDaemons implements Runnable{
@Override
public void run() {
while(true){
try{
TimeUnit.MILLISECONDS.sleep(200);
System.out.println(Thread.currentThread().getName());
} catch(InterruptedException e){
System.out.println(Thread.currentThread().getName() + " : InterruptException!");
e.printStackTrace();
}
}
}
}
public class Main{
public static void main(String[] args) throws InterruptedException{
for(int i=0; i<10; ++i){
Thread daemon = new Thread(new SimpleDaemons());
daemon.setDaemon(true);
daemon.start();
}
System.out.println("All daemons started");
TimeUnit.MILLISECONDS.sleep(1000);
}
}
所谓后台线程,是指程序运行的时候在后台提供一种通用的服务的线程,并且这种线程并不属于程序中不可或缺的部分。因此,当所有的非后台线程结束时,程序也就终止了,同时会杀死进程中的所有的后台线程。反过来说,只要任何非后台线程还在运行,程序就不会终止。
通过定制自己的ThreadFactory, 可以定制有Executor创建的线程的属性(后台,优先级,名称)
class DaemonThreadFactory implements ThreadFactory{
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
}
class DaemonFromFactory implements Runnable{
@Override
public void run() {
try{
TimeUnit.MILLISECONDS.sleep(100);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
public class Main{
public static void main(String[] args) throws InterruptedException{
ExecutorService exes = Executors.newCachedThreadPool(new DaemonThreadFactory());
for(int i=0; i<5; ++i)
exes.execute(new DaemonFromFactory());
System.out.println("All Daemos Started!");
TimeUnit.MILLISECONDS.sleep(1000);
}
}
java使用Executor(执行器)管理线程的更多相关文章
- Java的Executor框架和线程池实现原理
Java的Executor框架 1,Executor接口 public interface Executor { void execute(Runnable command); } Executor接 ...
- java笔记--用ThreadLocal管理线程,Callable<V>接口实现有返回值的线程
用ThreadLocal管理线程,Callable<V>接口实现有返回值的线程 ThreadLocal在我的笔记"关于线程同步"的第5种方式里面有介绍,这里就不多说了. ...
- Java的Executor框架和线程池实现原理(转)
ExecutorService接口继承自Executor接口,定义了终止.提交,执行任务.跟踪任务返回结果等方法 1,execute(Runnable command):履行Ruannable类型的任 ...
- 使用Executor管理线程
上一篇博客(第一个并发程序:定义任务和驱动任务)中,我们使用Thread对象启动线程,而java.util.concurrent包的Executor执行器提供了更好的管理Thread对象的方法,从而简 ...
- Java多线程——<三>简单的线程执行:Executor
一.概述 按照<Java多线程——<一><二>>中所讲,我们要使用线程,目前都是显示的声明Thread,并调用其start()方法.多线程并行,明显我们需要声明多个 ...
- java并发编程(十七)Executor框架和线程池
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17465497 Executor框架简介 在Java 5之后,并发编程引入了一堆新的启动 ...
- 转:【Java并发编程】之十九:并发新特性—Executor框架与线程池(含代码)
Executor框架简介 在Java5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.coc ...
- Java 并发编程——Executor框架和线程池原理
Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...
- 【Java并发编程】:并发新特性—Executor框架与线程池
Executor框架简介 在Java5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocur ...
随机推荐
- Code[VS] 1230 题解
1230 元素查找 题目描述 Description 给出n个正整数,然后有m个询问,每个询问一个整数,询问该整数是否在n个正整数中出现过. 输入描述 Input Description 第一行两个整 ...
- View的滑动
View的滑动 通过三种方式可以实现View的滑动: 1.通过View本身提供的scrollTo/scrollBy方法来实现滑动 2.通过动画给View施加平移效果来实现滑动 3.通过改变View的L ...
- python实现最简单的计算器功能源码
import re def calc(formula): formula = re.sub(' ', '', formula) formula_ret = 0 match_brackets = re. ...
- web前端笔试选择题
1. 要动态改变层中内容可以使用的方法有(AB ) a)innerHTML b)innerText c)通过设置层的隐藏和显示来实现 d)通过设置层的样式属性的display属性 2. 当按键盘A时, ...
- 搭建ssh后的简化
对于SSh框架的简化,我们可以从下面几个方面来剖析: 1.实体类entity 2.注入 3.类注解 下面,我来一一为大家讲解.ps:写的不好还请多多指教,欢迎大家"来找茬". 关于 ...
- Python之路第一课Day11--随堂笔记(异步IO\数据库\队列\缓存之二)
一.RabbitMQ队列 1.安装: a.官网: 安装 http://www.rabbitmq.com/install-standalone-mac.html b.安装python rabbitMQ ...
- centos下为大硬盘分区(大于2T)
问题:centos/redhat下使用分区工具fdisk创建大于2TB的分区,无法创建 关键字:MBR.GPT.CHS.LBA MBR:主引导记录 GPT:GUID 分区表 CHS:磁柱 磁头 扇区 ...
- canvas 学习
<!DOCTYPE html><html lang="en"><head> <meta charset="utf-8" ...
- XMLHTTPRequest对象的创建与浏览器的兼容问题
MLHttpRequest 对象是AJAX功能的核心,要开发AJAX程序必须从了解XMLHttpRequest 对象开始. 了解XMLHttpRequest 对象就先从创建XMLHttpRequest ...
- Java读写文件的几种方法
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java ...