public 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.print(status());
Thread.yield();
}
}
public static void main(String[] args){
for(int i=0; i<5; i++)
new Thread(new LiftOff()).start();
System.out.println("Waiting for LiftOff");
}
}/* Output
#1(9)#1(8)#2(9)#0(9)#2(8)#0(8)#0(7)#0(6)#0(5)#0(4)#0(3)#0(2)#0(1)#0(Liftoff!)#1(7)#3(9)Waiting for LiftOff
#2(7)#4(9)#3(8)#1(6)#3(7)#4(8)#2(6)#4(7)#2(5)#2(4)#2(3)#2(2)#2(1)#2(Liftoff!)#3(6)#3(5)#3(4)#3(3)#1(5)#3(2)#3(1)#3(Liftoff!)#4(6)#1(4)#4(5)#4(4)#1(3)#1(2)#1(1)#1(Liftoff!)#4(3)#4(2)#4(1)#4(Liftoff!)<<< Process finished (PID=15764). (Exit code 0)
*///:~
程序中Thread.yield()声明“我已经执行完生命周期中最重要的部分了,此刻正是切换给其他任务执行一段时间的一个大好时机。”其中,Thread构造器只需要一个Runnable对象,并通过start()方法运行对应对象的run()方法。
不过通常使用Executor来实现对线程的管理,并使用execute来提交Runnable对象。
import java.util.concurrent.*;
public class CachedThreadPool{
public static void main(String[] args){
ExecutorService exec = Executors.newCachedThreadPool();
// ExecutorService exec = Executors.newFixedThreadPool();
for(int i=0; i<5; i++)
exec.execute(new LiftOff());
exec.shutdown();
}
}/*Output
#1(9)#0(9)#3(9)#4(9)#2(9)#4(8)#3(8)#0(8)#1(8)#0(7)#0(6)#0(5)#3(7)#4(7)#2(8)#4(6)
#4(5)#4(4)#3(6)#0(4)#1(7)#0(3)#3(5)#4(3)#2(7)#4(2)#3(4)#0(2)#1(6)#0(1)#3(3)#4(1)
#4(Liftoff!)#2(6)#3(2)#0(Liftoff!)#1(5)#3(1)#2(5)#3(Liftoff!)#1(4)#2(4)#1(3)#2(3
)#2(2)#1(2)#2(1)#1(1)#2(Liftoff!)#1(Liftoff!)
*///:~
其中shutdown()方法可以防止新任务被提交给这个Executor。同时可以声明SingleThreadExecutor来限制线程数量为1,此时如果对其提交多个任务,那么这些任务将顺序执行。
import java.util.concurrent.*;
public class SingleThreadExecutor{
public static void main(String[] args){
ExecutorService exec = Executors.newSingleThreadExecutor();
for(int i=0; i<5; i++)
exec.execute(new LiftOff());
exec.shutdown();
}
}/*Output
#0(9)#0(8)#0(7)#0(6)#0(5)#0(4)#0(3)#0(2)#0(1)#0(Liftoff!)#1(9)#1(8)#1(7)#1(6)#1(
5)#1(4)#1(3)#1(2)#1(1)#1(Liftoff!)#2(9)#2(8)#2(7)#2(6)#2(5)#2(4)#2(3)#2(2)#2(1)#
2(Liftoff!)#3(9)#3(8)#3(7)#3(6)#3(5)#3(4)#3(3)#3(2)#3(1)#3(Liftoff!)#4(9)#4(8)#4
(7)#4(6)#4(5)#4(4)#4(3)#4(2)#4(1)#4(Liftoff!)
*///:~
如果需要线程具有返回值,可实现Callable接口
import java.util.concurrent.*;
import java.util.*;
class TaskWithResult implements Callable{
private int id;
public TaskWithResult(int id){
this.id = id;
}
public String call(){
return "result of TaskWithResult " + id;
}
}
public class CallableDemo{
public static void main(String[] args){
ExecutorService exec = Executors.newCachedThreadPool();
ArrayList> results = new ArrayList>();
for(int i=0; i<5; i++)
results.add(exec.submit(new TaskWithResult(i)));
for(Future fs : results){
try{
System.out.println(fs.get(200, TimeUnit.MILLISECONDS));
}
catch(TimeoutException e){
System.out.println(e);
return;
}
catch(InterruptedException e){
System.out.println(e);
return;
}
catch(ExecutionException e){
System.out.println(e);
}
finally{
exec.shutdown();
}
}
}
}/* Output
result of TaskWithResult 0
result of TaskWithResult 1
result of TaskWithResult 2
result of TaskWithResult 3
result of TaskWithResult 4
*///:~
使用submit()来提交Callable对象,并将返回值放入Future中。同时,可以通过Future对象get()来获取返回值,并指定运行时间。同时,submit()也能够提交Runnable对象,但是此时由于没有返回值,调用方式为
Future> f = exec.submit(Runnable())
不过此时将不能使用get方法来获取返回值。其通常的作用是通过f来调用cancel方法来实现对指定线程发送中断信号。
public void run(){
try{
// Old-style
Thread.sleep(100);
// Java SE5/~-style
TimeUnit.MILLISECONDS.sleep(100);
}
catch(InterruptedException e){
System.err.println("Interrupted");
}
}
import java.util.concurrent.*;
public class SimplePriorities implements Runnable{
private int countDown = 5;
private volatile double d;
private int priority;
public SimplePriorities(int priority){
this.priority = priority;
}
public String toString(){
return Thread.currentThread() + ": " + countDown;
}
public void run(){
Thread.currentThread().setPriority(priority);
while(true){
for(int i=1; i<100000; i++){
d += (Math.PI + Math.E)/(double)i;
if(i%1000 == 0)
Thread.yield();
}
System.out.println(this);
if(--countDown == 0) return;
}
}
public static void main(String[] args){
ExecutorService exec = Executors.newCachedThreadPool();
for(int i=0; i<5; i++)
exec.execute(new SimplePriorities(Thread.MIN_PRIORITY));
exec.execute(new SimplePriorities(Thread.MAX_PRIORITY));
exec.shutdown();
}
}/* Output
Thread[pool-1-thread-1,1,main]: 5
Thread[pool-1-thread-6,10,main]: 5
Thread[pool-1-thread-5,1,main]: 5
Thread[pool-1-thread-5,1,main]: 4
Thread[pool-1-thread-5,1,main]: 3
Thread[pool-1-thread-2,1,main]: 5
Thread[pool-1-thread-3,1,main]: 5
Thread[pool-1-thread-4,1,main]: 5
Thread[pool-1-thread-5,1,main]: 2
Thread[pool-1-thread-2,1,main]: 4
Thread[pool-1-thread-1,1,main]: 4
Thread[pool-1-thread-6,10,main]: 4
Thread[pool-1-thread-5,1,main]: 1
Thread[pool-1-thread-2,1,main]: 3
Thread[pool-1-thread-3,1,main]: 4
Thread[pool-1-thread-4,1,main]: 4
Thread[pool-1-thread-6,10,main]: 3
Thread[pool-1-thread-2,1,main]: 2
Thread[pool-1-thread-1,1,main]: 3
Thread[pool-1-thread-6,10,main]: 2
Thread[pool-1-thread-2,1,main]: 1
Thread[pool-1-thread-1,1,main]: 2
Thread[pool-1-thread-4,1,main]: 3
Thread[pool-1-thread-3,1,main]: 3
Thread[pool-1-thread-6,10,main]: 1
Thread[pool-1-thread-4,1,main]: 2
Thread[pool-1-thread-1,1,main]: 1
Thread[pool-1-thread-3,1,main]: 2
Thread[pool-1-thread-4,1,main]: 1
Thread[pool-1-thread-3,1,main]: 1
*///:~
由于本系统是多核处理器,所以没有出现先完全执行pool-1-thread-6的情形。需要注意的是,唯一可移植的优先级只包括MAX_PRIORITY,NORM_PRIORITY,MIN_PRIORITY。
后台线程并不属于程序中不可或缺的部分。因此当所有非后台线程结束时,程序也就终止,同时会杀死进程中的所有后台线程(直接终止)。在启动后台线程时,必须在启动前先使用 daemon.setDaemon(true) 将线程设置为后台线程。同时,如果是一个后台线程,那么它创建的任何线程都将自动设置为后台线程。
除了以上显示定义并启动线程的方式,还可以通过继承Thread、实现Runnable接口或者内部类(匿名内部类)来实现。
ThreadName.join():调用线程将等待ThreadName线程结束之后再运行
ThreadName.interrupt():中断ThreadName线程的执行
import java.util.concurrent.*;
class ExceptionThread implements Runnable{
public void run(){
Thread t = Thread.currentThread();
System.out.println("run() by " + t);
System.out.println("eh = " + t.getUncaughtExceptionHandler());
throw new RuntimeException();
}
}
class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
public void uncaughtException(Thread t, Throwable e){
System.out.println("caught " + e);
}
}
class HandlerThreadFactory implements ThreadFactory{
public Thread newThread(Runnable r){
System.out.println(this + " creating new Thread");
Thread t = new Thread(r);
System.out.println("created " + t);
t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
System.out.println("eh = " + t.getUncaughtExceptionHandler());
return t;
}
}
public class CaptureUncaughtException{
public static void main(String[] args){
ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
exec.execute(new ExceptionThread());
// define a default uncaught exception handler
// Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
// ExecutorService exec = Executors.newCachedThreadPool();
// exec.execute(new ExceptionThread());
}
}/* Output
HandlerThreadFactory@4e25154f creating new Thread
created Thread[Thread-0,5,main]
eh = MyUncaughtExceptionHandler@70dea4e
run() by Thread[Thread-0,5,main]
eh = MyUncaughtExceptionHandler@70dea4e
HandlerThreadFactory@4e25154f creating new Thread
created Thread[Thread-1,5,main]
eh = MyUncaughtExceptionHandler@7a88bb53
caught java.lang.RuntimeException
*///:~
线程run()方法中的异常需要通过设置UncaughtExceptionHandler来捕获,也可以通过定义一个默认的未捕获异常处理器,在没有定义专有处理器时被调用。