实现多线程的方式
一、使用Thread实现多线程
定义一个任务,用Runnable来描述。
//打印任务
class PrintRunnable implements Runnable {
private int num=0;
public void run() {
boolean isfinished=false;
while(!isfinished){
if(num==200){//i为200时结束
isfinished=true;
break;
}
System.out.println(num++);
}
}
}
调用方式
public static void main(String[] args){
Thread thread =new Thread(new PrintRunnable());
thread.start();
}
二、使用Executors和Future实现多线程
public static void main(String[] args){
//产生线程池
ExecutorService exec = Executors.newSingleThreadExecutor();
//ExecutorService exec = Executors.newCachedThreadPool();
//ExecutorService exec = Executors.newFixedThreadPool(5);
//执行任务
exec.execute(new PrintRunnable());
//关闭
exec.shutdown();
}
三、实现带返回结果的多线程
定义带返回结果的任务,用Callable描述。
//并返回结果的打印任务
class PrintCallable implements Callable<Integer>{
private int num=0;
@Override
public Integer call() throws Exception {
boolean isfinished=false;
while(!isfinished){
if(num==200){//i为200时结束
isfinished=true;
break;
}
System.out.println(num++);
}
//返回结果
return num;
}
}
调用方式
public static void main(String[] args){
//产生线程池
ExecutorService exec = Executors.newSingleThreadExecutor();
//ExecutorService exec = Executors.newCachedThreadPool();
//ExecutorService exec = Executors.newFixedThreadPool(5);
//执行任务
exec.execute(new PrintRunnable());
//关闭
exec.shutdown();
//提交并执行带返回结果的任务
Future<Integer> future = exec.submit(new PrintCallable());
try {
//获取返回结果.get方法会阻塞,直到结果返回
System.out.println(future.get());
System.out.println(future.get(5, TimeUnit.MINUTES));//指定超时时间5s
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
几种方式的比较
尽量不直接使用线程,因为线程既充当的工作单元,又是执行机制。而使用Execute则将工作单元和执行机制优雅的分开了。工作单元指的是任务(task),包括Runnable任务和Callable任务。
选择哪种线程池
Executors.newCachedTheadPool:
对于小程序和轻载的服务器,我们可以使用它是个不错的选择
Executors.newFixedThreadPool:
对于大负载的服务器来说,缓存的线程池就不是很好的选择了!在缓存的线程池中,被提交的任务没有排成队,而是直接交给线程执行。如果没有线程可用,则创建新的线程,如若如武器负载较重,以致它所有的cpu都完全被占用,当有更多任务时,则会创建更多的线程,情况则会变得更糟。因此,在大负载的产品服务器中,最好使用Executors.newFixedThreadPool。或者为了最大限度的控制它,可以直接使用ThreadPoolExecutor类。
Executors.newSingleThreadExecutor:
对于在希望在另一个线程中连续运行的事物(长期存活的任务)来说,都是很有用的,例如监听进入的socket连接的任务。对希望在线程中运行的段任务也同样方便。例如,更新本地或远程日志的小任务,或者是事件分发线程。
本文参考了《java编程思想》第4版和《Effective Java中文版》第2版