从java5开始,类库中引入了很多新的管理调度线程的API,最常用的就是Executor(执行器)框架。Executor帮助程序员管理Thread对象,简化了并发编程,它其实就是在 提供了一个中间层,方便程序员管理异步任务的执行,而又不用显式的管理线程的生命周期。
Executor采用了线程池实现,也更节约开销,因为是我们启动新线程的首选方法。
示例代码:src/thread_runnable/CachedThreadPool.java
public class CachedThreadPool{ public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool(); System.out.println("main start " + Thread.currentThread().getName());
for (int i=0; i<3; i++){
exec.execute(new CountDown());
} exec.shutdown();
System.out.println("main end " + Thread.currentThread().getName());
} }
输出结果:(每次执行输出结果都有差异)
Executors类通过提供一系列的工厂方法来创建线程池,返回的线程池都实现了ExecutorService接口,ExecutorService接口实现了Executor接口,提供了更丰富的方法来管理线程池,ExecutorService对象可以通过execute(Runnable)/submit(Callable)方法来开始执行新的方法(这本身也属于命令设计模式)。
ExecutorService(其实就是线程池)的生命周期包括三种状态,运行,关闭,终止。创建后便进入运行状态。调用shutdown()方法就进入关闭状态。此时ExecutorService不再接受新的任务,但是它还在执行已经提交的任务,等到所有的任务都执行完毕后,就到了终止状态。
Executors类通过提供一系列的工厂方法来创建线程池,常见类型如下:
public static ExecutorService newFixedThreadPool(int nThreads)
创建固定数目的线程池
public static ExecutorService newCachedThreadPool()
创建一个可缓存的线程池,调用execute添加新任务后,如果有之前构造的可用线程,则重用该线程;否则,就创建一个新线程并添加到池中。并且可以从缓存中移除那些60s未被使用的线程。
public static ExecutorService newSingleThreadExecutor()
创建一个单线程的线程池。其实只有一个线程,所有的任务按照指定的顺序,(FIFO,LIFO,优先级)来执行。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个定长线程池,支持定时及周期性的任务执行,所以很多时候可用来代替Timer类。
看一个简单的例子,代码地址:src/thread_runnable/FixedThreadPool.java
public class FixedThreadPool{
public static void main(String[] args) {
int ThreadCount = 2;
ExecutorService exec = Executors.newFixedThreadPool(ThreadCount); System.out.println("main start " + Thread.currentThread().getName());
for (int i=0; i<3; i++){
exec.execute(new CountDown());
}
exec.shutdown();
System.out.println("main end " + Thread.currentThread().getName()); }
}
当ThreadCount = 2时,某一次输出结果为:
从输出结果可以看出,在最初的时候,只有thread-1和thread-2两个线程在执行任务,当之前的任务执行完成之后,thread-2被复用,开始执行第三个任务。
那么我们可以想象,如果我们把 让ThreadCount = 1,那么应该只存在一个线程,其执行完一个任务,再接着执行另一个。
修改ThreadCount = 1,输出结果符合我们的预期:
可以周期或者delay执行的 线程也是在实际项目中也是比较常见的。
示例代码地址:src\thread_runnable\ScheduledExecutorServiceDemo.java
public class ScheduledExecutorServiceDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
ScheduledExecutorService mScheduledService = Executors.newScheduledThreadPool(2);
System.out.println("ScheduledExecutorServiceDemo --- main start, " + Thread.currentThread().getName());
mScheduledService.schedule(new CountDown(), 2 , TimeUnit.SECONDS);
System.out.println("ScheduledExecutorServiceDemo --- main end, " + Thread.currentThread().getName());
mScheduledService.shutdown();
}
}
输出结果:(通过实际输出,可以看到 ,两秒钟之后,才开始执行任务当中的打印 语句)
关于周期性任务的demo。
示例代码地址:src\thread_runnable\ScheduledFixedServiceDemo_2.java
public class ScheduledFixedServiceDemo_2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
ScheduledExecutorService mScheduledService = Executors.newScheduledThreadPool(2);
System.out.println("ScheduledFixedServiceDemo_2 --- main start, " + Thread.currentThread().getName());
mScheduledService.scheduleWithFixedDelay(new Runnable() {
int count = 0;
@Override
public void run() {
System.out.println("fixed print = " + count++); }
}, 1, 2 , TimeUnit.SECONDS);
System.out.println("ScheduledFixedServiceDemo_2 --- main end, " + Thread.currentThread().getName());
}
}
输出结果:
…..后面每间隔2s,输出一次。
Runnable虽然执行任务,但是没有返回值,而java 5之后 ,重新引入了一个 Callable接口,它是一个具有类型参数的泛型,表示从call()方法中返回的值。不过需要注意的是,把Callable对象传递给ExecutorService的submit方法后,在新线程上执行的call()方法返回的其实是 Future对象,Future对象有isDone(),get()等方法来判断是否完成,以及得到返回值等。
代码地址:src\thread_runnable\CallableDemo.java
class TaskWithResult implements Callable<String> {
public String call() throws Exception {
return "result of TaskWithResult from Callable " + "\t " + Thread.currentThread().getName();
}
} public class CallableDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
ExecutorService exec = Executors.newCachedThreadPool(); System.out.println("main start\t" + Thread.currentThread().getName());
Future<String> fs = exec.submit(new TaskWithResult());
exec.shutdown(); try {
//当callable对象并没有完成时,这里一直是堵塞的。
System.out.println(fs.get());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("main end\t" + Thread.currentThread().getName());
}
}
输出结果:
这几篇java多线程文章的demo代码下载地址 http://download.csdn.net/detail/yaowen369/9786452
-------
作者: www.yaoxiaowen.com
github: https://github.com/yaowen369