1.Runnable接口与Callable接口的区别
Runnable接口中的方法签名为:public void run();该方法不能声明抛出受检查的异常,但在方法体内可以捕获并处理异常;
Callable<V>接口中的方法签名:public V call() throws Exception;该方法能够抛出受检查的异常,能够返回一个V类型的值;
实现这两个接口的对象都可以用来构造线程对象。
2.Future<V>接口
该接口能够封装Callable接口的返回值,并提供了一系列的方法来获取call方法的计算结果。
- boolean cancel(boolean mayInterruptIfRunning):该方法试图取消对任务的执行;
- boolean isCancelled():如果在任务正常完成前将其取消,则返回 true;
- boolean isDone():如果任务已完成,则返回 true。 可能由于正常终止、异常或取消而完成,在所有这些情况中,此方法都将返回 true;
- V get():如有必要,则阻塞等待计算完成,然后获取其结果;
- V get(long timeout, TimeUnit unit):如有必要,最多等待为使计算完成所给定的时间之后,获取其结果,否则抛出异常
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
class RetString implements Callable<String>{
private String retString;
public RetString(String s) {
this.retString = s;
}
public String call() throws Exception{
return retString;
}
}
public class CallableThreadTest {
public static void main(String[] args) throws
InterruptedException, ExecutionException {
/**
* 使用Future接口,需要使用submit方法提交任务,该方法返回一个future对象
*/
ExecutorService exec = Executors.newFixedThreadPool(2);
Future<String> future = exec.submit(new RetString("Hello World"));
/**
* 使用FutureTask类,直接使用execute方法
*/
FutureTask<String> fTask = new FutureTask<String>(new RetString("Good Night"));
exec.execute(fTask);
if(future.isDone())
System.out.println(future.get());
if(fTask.isDone())
System.out.println(fTask.get());
exec.shutdown();
}
}
3.使用Executor
该接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法;ExecutorService是该接口的一个子接口。通过Executors工厂类的静态方法来创建ExecutorService接口对象。
- static ExecutorService newCachedThreadPool():创建一个可根据需要创建新线程的线程池;
- static ExecutorService newCachedThreadPool(ThreadFactory threadFactory):创建一个可根据需要创建新线程的线程池,在需要时使用提供的 ThreadFactory 创建新线程;
- static ExecutorService newFixedThreadPool(int nThreads):创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程;
- static ExecutorService newFixedThreadPool(int nThreads,ThreadFactory threadFactory);
- static ExecutorService newSingleThreadExecutor():创建一个使用单个worker线程的Executor,以无界队列方式来运行该线程。如果提交多个任务,这些任务将排队,每个任务在下个任务开始i之前运行结束;
- static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) :创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
- static ScheduledExecutorService newSingleThreadScheduledExecutor() :创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
class SimpleThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) { //需要要实现的方法
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
}
可通过下面的方法向ExecutorService提交要执行的任务和关闭任务:
- Future<T> submit(Callable<T> task):提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future;
- Future<?> submit(Runnable task):提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future;结束后返回null;
- <T> Future<T> submit(Runnable task, T result):提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。该 Future 的 get 方法在成功完成时将会返回给定的结果T;
- void execute(Runnable command):在未来某个时间执行给定的命令。该命令可能在新的线程、已入池的线程或者正调用的线程中执行,这由 Executor 实现决定
- void shutdown():启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用。
- List<Runnable> shutdownNow():试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表,该方法其实是发送interrupt()调用给它启动的所有线程;
- <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit):创建并执行在给定延迟后启用的ScheduledFuture;
- ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) :创建并执行在给定延迟后启用的一次性操作,在delay后执行
- ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;也就是将在 initialDelay 后开始执行,然后在 initialDelay+period 后执行,接着在 initialDelay + 2 * period 后执行,依此类推;
- ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) :创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟
4.线程中断
Thread.interrupt()方法不会中断一个正在运行的线程。这一方法实际上完成的是,在线程受到阻塞或者正在尝试阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态。更确切的说,如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,那么,它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。当抛出异常或者调用Thread.interrupted()时,中断状态将被复位。所以,只有在Object.wait, Thread.join和Thread.sleep这三个方法上已经阻塞或者尝试阻塞的线程,当中断位被设置时,才会抛出异常,中断状态被清除,否则中断不会真正中断线程的执行。I/O和在synchronized块上的等待是不可中断的,可以通过关闭任务在其上发生阻塞的底层资源来中断。
5.捕获线程异常
异常不能跨线程传播,因此其他线程中抛出的异常不会传播到Main线程。Thread.UncaughtExceptionHandler接口允许在每个Thread对象上附着一个异常处理器。该接口中的方法声明为:public void uncaughtException(Thread t, Throwable e);对线程对象调用setUncaughtExceptionHandler()方法可以为线程设置异常处理器。