package booknote.chapter21_并发;
/**
* 一个线程就是在进程中的一个单一的顺序控制流
* web库的基本类Servlet具有天生的多线程性,因为web服务器经常包含多个处理器,而并发是充分利用这些处理器的理想方式
*/
public class ThreadNote {
/**
* 定义任务:一个public的内部类
* 当从Runnable导出一个类时,它必须具有run()方法,但是这个方法并无特殊之处,它不会产生任何内在的线程能力。
* 要实现线程行为,则必须显示地将一个任务附着到线程上 。
*/
public static class Liftoff implements Runnable{
protected int countDown = 10;
private static int taskCount = 0;
private final int id = taskCount++;
public Liftoff(){
}
public Liftoff(int countDown){
this.countDown = countDown;
}
public String status(){
return "#"+id+"("+ (countDown>0?countDown:"Liftoff!")+")";
}
public void run(){
while(countDown-->0){
System.out.println(status());
/**
* 对静态方法Thread.yield()的调用时对线程调度器:
* java线程机制的一部分,可以将cpu从一个线程转移给另一个线程
* 相当于声明:我已经执行完生命周期中最重要的部分了,此刻正是切换给其他任务执行一段时间的大好时机
*/
Thread.yield();
}
}
}
/**
* 在main()线程中创建新定义的执行任务的线程
*/
public static void main(String[] args) {
for(int i=0;i<5;i++){
/**
* Thread构造器只需要一个Runnable对象。
* 调用Thread对象的start()方法为该线程执行必需的初始化操作,然后调用Runnable的run()方法,以便在新线程中启动该任务。
* Start()看起来是产生了一个对长期运行方法的调用,实际上产生的是对Liftoff.run()的方法调用,
* 就算这个方法还没有完成,但是因为Liftoff.run()是由不同的线程执行的,因此仍旧可以执行main()线程中的其他操作
* (任何线程都可以启动另一个线程),因此程序看起来会同时运行两个方法main(),Liftoff.run()
*/
/**
* 当main()创建Thread对象时,它并没有捕获任何对这些对象的引用。
* 在使用普通对象时,这对于垃圾回收来说是一场公平游戏,但是使用Thread时,情况会不同。
* 每个Thred都"注册了自己,因此确实有一个对它的引用,而且在它的任务退出其run()并死亡之前,垃圾回收器无法清除它。
* 因此,一个线程会创建一个单独的执行线程,在对start()的调用完成之后,它仍旧会继续存在。"
*/
new Thread(new Liftoff()).start();
System.out.println("waiting for liftoff!");
}
}
}
package booknote.chapter21_并发;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import booknote.chapter21_并发.ThreadNote.Liftoff;
/**
* JAVA SE5的java.util.concurrent包中的执行器Executor用来管理Thread对象,从而简化并发编程。
* Executor在客户端和任务执行之间提供了一个间接层;与客户端直接执行任务不同,这个中介对象将执行任务。
* Executor允许你管理异步任务的执行,而无须显示地管理线程的生命周期。
*/
public class CachedThreadPool {
public static void main(String[] args) {
//ExecutorService对象是使用静态的Executor方法创建,这个方法可以确定其Executor类型
ExecutorService exec =Executors.newCachedThreadPool();
for(int i=0;i<5;i++){
exec.execute(new Liftoff());
}
exec.shutdown();
/**
* FixedThreadPool使用有限的线程集来执行所提交的任务,即一次性预先执行代价高昂的线程分配,因而就可以限制线程的数量了。
* 这样可以节省时间,因为你不用为每个任务都固定地付出创建线程的开销。
* 注意:在任何线程池中,现有线程在可能的情况下,都会被自动复用。
*
* CachedThreadPool在程序执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程,因此它是合理的
* Executor的首选。只有当这种方式会引发问题时,你才需要切换到FixedThreadPool
*/
ExecutorService exec2 =Executors.newFixedThreadPool(5);
for(int i=0;i<5;i++){
exec2.execute(new Liftoff());
}
exec2.shutdown();
}
}