@XQF
2017-02-17T15:05:32.000000Z
字数 4704
阅读 1772
java
我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。
那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务?
class TestRunnable implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName() + "线程被调用了。");
}
}
public class TestCachedThreadPool {
public static void main(String[] args) {
// 1、创建一个单线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();
//2、往线程池中添加任务
for (int i = 0; i < 5; i++) {
executorService.execute(new TestRunnable());
System.out.println("************* a" + i + " *************");
}
// 3、关闭线程池
executorService.shutdown();
}
}
Executors提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。
//创建固定数目线程的线程池
public static ExecutorService newFixedThreadPool(int nThreads)
//创建一个可缓存的线程池,调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线 程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
public static ExecutorService newCachedThreadPool()
//创建一个单线程化的Executor。
public static ExecutorService newSingleThreadExecutor()
//创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
使用executorService的execute()方法将任务添加到线程,线程就会自动的执行Runnable的run方法。
ExecutorService的生命周期包括三种状态:运行、关闭、终止。创建后便进入运行状态,当调用了shutdown()方法时,便进入关闭状态,此时意味着ExecutorService不再接受新的任务,但它还在执行已经提交了的任务,当所有已经提交了的任务执行完后,便到达终止状态。如果不调用shutdown()方法,ExecutorService会一直处在运行状态,不断接收新的任务,执行新的任务,服务器端一般不需要关闭它,保持一直运行即可。
Callable任务与Runnable任务不同的就是Callable任务有返回值,任务执行完成之后,它可以得到任务的返回值。返回Future对象,我们可以根据这个对象的isDone函数来判断是否这个对象已经得到了返回值,如果为ture,就表示已经得到了返回值,这样我使用Future的get方法就可以得到任务的返回值。
class TaskWithResult implements Callable<String> {
private int id;
public TaskWithResult(int id) {
this.id = id;
}
/**
* 任务的具体过程,一旦任务传给ExecutorService的submit方法,
* 则该方法自动在一个线程上执行
*/
public String call() throws Exception {
System.out.println("call()方法被自动调用!!! " + Thread.currentThread().getName());
//该返回结果将被Future的get方法得到
return "call()方法被自动调用,任务返回的结果是:" + id + " " + Thread.currentThread().getName();
}
}
public class CallableDemo {
public static void main(String[] args) {
// 1、创建一个线程池
ExecutorService executorService = Executors.newCachedThreadPool();
// 创建一个List来存放任务的返回future
List<Future<String>> resultList = new ArrayList<>();
//创建10个任务并执行
for (int i = 0; i < 10; i++) {
//2、向线程中添加Callable任务,Callable任务的返回值存放在future中
Future<String> future = executorService.submit(new TaskWithResult(i));
//将任务执行结果存储到List中
resultList.add(future);
}
//遍历任务的结果
for (Future<String> fs : resultList) {
try {
//Future返回如果没有完成,则一直循环等待,直到Future返回完成
while (!fs.isDone()) ;
//打印各个任务返回的结果
System.out.println(fs.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
//3、关闭线程池
executorService.shutdown();
}
}
}
}
跟上面一样
这个跟上面的不同就是它可以得到一个返回值future,我们可以通过future里面的isDone()函数来判断是否结果以及被返回,如果Callable任务的结果还没有被返回,isDone函数的结果为false,否则为true,这样就可以通过future的get方法得到返回值,其实我们也可以不用判断,直接调用get函数,如果任务没有返回结果,他会被阻塞,直到结果返回。使用executorService的submit函数将任务添加到线程,线程会自动调用它的call方法。
跟上面一样
FutureTask有一个cancel方法,我们可以调用这个方法来取消任务,如果任务被取消,那么任务就不会被运行。另外它也具备第二种方法的优点,它可以得到返回结果,不过不是通过返回值的形式。
class DemoTask implements Callable<String> {
public String call() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println(e);
}
return "Task Done";
}
}
public class FutureTaskDemo {
public static void main(String... args) throws InterruptedException, ExecutionException {
// 1、创建一个线程池
ExecutorService exService = Executors.newSingleThreadExecutor();
// 2、创建一个FutureTask任务
FutureTask<String> futureTask = new FutureTask<>(new DemoTask());
// 3、将任务放入线程池
exService.execute(futureTask);
//检测任务是否执行完成
System.out.println(futureTask.isDone());
//检测任务是否被取消
System.out.println(futureTask.isCancelled());
//获取返回结果
System.out.println(futureTask.get());
}
跟上面的一样
execute()方法或者submit()方法都行
用ThreadPoolExecutor类创建线程池,我们直接来看代码。
class MyThread implements Runnable{
@Override
public void run(){
System.out.println(Thread.currentThread().getName() + "正在执行。。。");
try{
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
public class ThreadPoolTest{
public static void main(String[] args){
//1、创建等待队列
BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<Runnable>(20);
//2、创建线程池,池中保存的线程数为3,允许的最大线程数为5
ThreadPoolExecutor pool = new ThreadPoolExecutor(3,5,50, TimeUnit.MILLISECONDS,bqueue);
Runnable t1 = new MyThread();
Runnable t2 = new MyThread();
Runnable t3 = new MyThread();
Runnable t4 = new MyThread();
Runnable t5 = new MyThread();
Runnable t6 = new MyThread();
Runnable t7 = new MyThread();
//3、向线程池添加任务
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
pool.execute(t6);
pool.execute(t7);
//4、关闭线程池
pool.shutdown();
}
}
注意等待队列