Thread学习
定义一个任务
- 实现Runnable接口,重写run()方法。
- 继承Thread类,重写run()方法。
//extends Thread public class LiftOff extends Thread{ 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") + ")."; } @Override public void run() { while(countDown-- > 0) { System.out.println(status()); Thread.yield();//yield提示系统该任务重要的部分已经完成,可以进行切换线程。 } } }
//implements Runnable 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") + ")."; } @Override public void run() { while(countDown-- > 0) { System.out.println(status()); Thread.yield(); } } }
创建一个线程 Thread
使用Thread创建一个线程,构造器需要一个实现run()方法的对象
public class MoreBasicThreads { public static void main(String[] args) { Thread thread1 = new Thread(new LiftOff()); Thread thread2 = new Thread(new LiftOff()); thread1.start(); thread2.start(); System.out.println("****"); } }
使用Executor
java.util.concurrent中提供了执行器(Executor)用于管理Thread对象。暴露了要执行的单一单元ExecutorService,用来构建执行线程。使用静态方法Executors来获取ExecutorService对象。ExecutorService种类:
- CachedThreadPool:每次有线程时创建新的线程。
- FixedThreadPool:一次性进行线程分配。可以节约时间。多个任务申请时,维护一个队列。
- SingleThreadPool:指定为一个线程的FixedThreadPool,多个任务申请时,维护一个队列,逐个执行。所有任务使用相同的线程。
Example:
public class CachedThreadPool { public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool();//获取ExecutorService对象 for(int i = 0; i < 5; i++) { service.execute(new LiftOff());//execute(Runnable)创建线程 } service.shutdown();//不在接受新的线程 System.out.println("***"); } }
获取返回值 Callable
实现Callable接口,Callable是一个泛型接口,指定返回值得类型。在Callable中方法call()用来执行任务并返回值。class TaskWithResult implements Callable<String> { private int id; public TaskWithResult(int id) { this.id = id; } @Override public String call() throws Exception { return "result to TaskWithResult " + id; } } public class CallableDemo { public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); ArrayList<Future<String>> results = new ArrayList<Future<String>>();//Callable<T>返回Future<T>类型 for(int i = 0; i < 5; i++) { results.add(service.submit(new TaskWithResult(i)));//使用submit进行创建线程 } for(Future<String> result : results) { System.out.println(result.isDone());//使用isDone()检测结果是否已经返回 try{ System.out.println(result.get());//通过get()获取返回值。如果值没用,就会堵塞,知道结果准备好。也可以使用带有超时的get } catch(Exception e) { e.printStackTrace(); } finally { System.out.println(result.isDone()); } } } }
捕获异常
异常在线程间不能传递,也就是说在线程内必须处理完线程的异常。
Thread.UncaughtExceptionHandler是Java SE5提供的新接口,当一个线程因为未处理的异常导致崩溃时,会调用Thread.UncaughtExceptionHandler.uncaughtException()方法用来处理。继承Thread.UncaughtExceptionHandler接口,实现uncaughtException方法。然后在线程中通过setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler)方法注册在线程中就可以完成处理异常了
class ExceptionThread2 implements Runnable{ public void run() { Thread t = Thread.currentThread();//获取当前的线程 System.out.println("run() by " + t); System.out.println("en = " + t.getUncaughtExceptionHandler()); throw new RuntimeException(); } } class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{ //实现Thread.UncaughtExceptionHandler接口,重写uncaughtException方法 public void uncaughtException(Thread t, Throwable e) { System.out.println("caught " + e); } } class HandlerThreadFactory implements ThreadFactory { //继承ThreadFactory接口,实现newThread(Runnable)接口,返回Thread public Thread newThread(Runnable r) { Thread thread = new Thread(r); System.out.println("created " + thread); thread.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); //setUncaughtExceptionHandler设置异常处理 System.out.println("en = " + thread.getUncaughtExceptionHandler()); return thread; } } public class CaptureUncaughtException { public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(new HandlerThreadFactory()); service.execute(new ExceptionThread2()); } }
常用方法
类 | 方法 | 含义 |
---|---|---|
Thread | sleep(s) | 休息毫秒,可能会返回InterruptedException,线程之间不会传递异常,所以需要在线程内解决产生的异常 |
Thread | yield() | 提示系统该任务重要的部分已经完成,可以进行切换线程。 |
Thread | currentThread() | 获取当前线程 |
Thread | setPriority(x) | 设置线程的优先级 |
Thread | setDaemon() | 设置为后台线程,后台线程时一种提供服务的线程。非后台线程结束时程序就会结束 |
Thread | isDaemon() | 判断是否是后台线程 |
Thread | join() | 自身挂起,等待调用线程结束后再执行。也可以设置超时时间 |
PS:
- ExecutorService会创建一个ThreadFactory对象,用来创建线程
- 构造器中启动线程,可能会导致线程另一个任务访问了不稳定状态的对象
- 异常不会跨线程传递,所以线程内要处理自身的异常