【多线程】线程池中的一些常见方法

时间:2021-06-27 00:01:11

1、submit()

       将线程放入线程池中,除了使用execute,也可以使用submit,它们两个的区别是一个使用有返回值,一个没有返回值。submit的方法很适应于生产者-消费者模式,通过和Future结合一起使用,可以起到如果线程没有返回结果,就阻塞当前线程等待线程 池结果返回。

它主要有三种方法:

一般用第一种比较多

【多线程】线程池中的一些常见方法

如下实例。注意,submit中的线程要实现接口Callable


package cn.qblank.thread;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class TaskWithResult implements Callable<String> {
    private int id;
    public TaskWithResult(int id) {
        this.id = id;
    }
    /**
     * 任务的具体过程,一旦任务传给ExecutorService的submit方法,则该方法自动在一个线程上执行
     * @return
     * @throws Exception
     */
    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName() + "call()方法被自动调用...");
        //模拟一个耗时的操作
        for (int i = 0; i < 999999; i++){

        }
        return Thread.currentThread().getName() + "call()方法被自动调用,任务的结果是:" + id;
    }


    //测试
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        List<Future<String>> resultList = new ArrayList<>();
        //创建10个任务并执行
        for (int i = 0; i < 10; i++) {
            //使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中
            Future<String> future = executorService.submit(new TaskWithResult(i));
            //将任务执行结果存储到集合中
            resultList.add(future);
        }
        //启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用。
        executorService.shutdown();
        //遍历任务结果
        for (Future<String> fs : resultList){
            try {
                //打印任务执行的结果
                System.out.println(fs.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
}

执行结果:

【多线程】线程池中的一些常见方法

从上面可以看到,输出结果的依次的。说明每次get都 阻塞了的。

看了下它的源码,其实它最终还是调用 了execute方法

[java]  view plain  copy
  1. public <T> Future<T> submit(Callable<T> task) {  
  2.     if (task == nullthrow new NullPointerException();  
  3.     RunnableFuture<T> ftask = newTaskFor(task);  
  4.     execute(ftask);  
  5.     return ftask;  
  6. }  
2、execute()

表示往线程池添加线程,有可能会立即运行,也有可能不会。无法预知线程何时开始,何时线束。

主要源码如下:

[java]  view plain  copy
  1. public void execute(Runnable command) {  
  2.     if (command == null)  
  3.         throw new NullPointerException();  
  4.     if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {  
  5.         if (runState == RUNNING && workQueue.offer(command)) {  
  6.             if (runState != RUNNING || poolSize == 0)  
  7.                 ensureQueuedTaskHandled(command);  
  8.         }  
  9.         else if (!addIfUnderMaximumPoolSize(command))  
  10.             reject(command); // is shutdown or saturated  
  11.     }  
  12. }  

3、shutdown()

通常放在execute后面。如果调用 了这个方法,一方面,表明当前线程池已不再接收新添加的线程,新添加的线程会被拒绝执行。另一方面,表明当所有线程执行完毕时,回收线程池的资源。注意,它不会马上关闭线程池!

4、shutdownNow()

不管当前有没有线程在执行,马上关闭线程池!这个方法要小心使用,要有可能会引起系统数据异常!


转自: https://blog.csdn.net/evankaka/article/details/51489322