zoukankan      html  css  js  c++  java
  • 多线程(三)

    接着说 线程池,使用java自带的线程池,一般的情况下线程池对应的实现类是ThreadPoolExecutor,当然不排除自己来写一个线程池,扯远了,ThreadPoolExecutor 扩展自抽象类AbstractExecutorService,其中AbstractExecutorService 默认的实现了:

    image

    默认的实现的方法中首先我们看看,上面我们说到的submit()方法:

    源代码:

    public Future<?> submit(Runnable task) {
            if (task == null) throw new NullPointerException();
            RunnableFuture<Object> ftask = newTaskFor(task, null);
            execute(ftask);
            return ftask;
        }
    
        public <T> Future<T> submit(Runnable task, T result) {
            if (task == null) throw new NullPointerException();
            RunnableFuture<T> ftask = newTaskFor(task, result);
            execute(ftask);
            return ftask;
        }
    
        public <T> Future<T> submit(Callable<T> task) {
            if (task == null) throw new NullPointerException();
            RunnableFuture<T> ftask = newTaskFor(task);
            execute(ftask);
            return ftask;
        }

    可以看到的是:

    针对submit()接受的参数的类型是实现了Runable 或者Callable 接口的类,然后封装为 RunnableFuture<T> ftask = newTaskFor(task);  交给execute(ftask)执行,返回执行的结果。这个execute(Runnable)方法将在子类ThreadPoolExecutor中实现。

    我们可以首先来看一下executor接口的说明:

    public interface Executor {
    
        /**
         * Executes the given command at some time in the future.  The command
         * may execute in a new thread, in a pooled thread, or in the calling
         * thread, at the discretion of the <tt>Executor</tt> implementation.
         *
         * @param command the runnable task
         * @throws RejectedExecutionException if this task cannot be
         * accepted for execution.
         * @throws NullPointerException if command is null
         */
        void execute(Runnable command);
    }

    在将来某个时刻执行给定的任务command,说明这个方法是将来会去执行,在主线程(submit方法)中是不会阻塞的。另外,注意到如果提交的是Runnable接口,返回的future对象中其结果是在任务提交时候就指定了的,要么是null,要么是T result。上面的分析可以简单测试下:

    //Callable 任务
    class CallabelTask implements Callable<String>{
            String name;
            public CallabelTask(String name){
                this.name = name;
            }
            @Override
            public String call() throws Exception {
                System.out.println("Start to execute the task " + name);
                TimeUnit.SECONDS.sleep(5);
                return name + " is done!";
            }
            
        }
    public static void submitCallableTask()throws Exception{
            ExecutorService executor = Executors.newCachedThreadPool();
            List<Future<String>> results = new ArrayList<Future<String>>(5);
            for(int i = 0; i < 5; ){
                results.add(executor.submit(new CallabelTask("task_"+(++i))));
            }
            System.out.println("All the tasks have been submited through invokeAll method!");
            executor.shutdown();
            for(Future<String> f : results)
                System.out.println(f.get());
        }
    public static void main(String[] args) throws Exception { submitCallableTask();
    }
    //调用submitCallableTask的结果:
    All the tasks have been submited through invokeAll method!
    Start to execute the task task_1
    Start to execute the task task_5
    Start to execute the task task_3
    Start to execute the task task_4
    Start to execute the task task_2
    task_1 is done!
    task_2 is done!
    task_3 is done!
    task_4 is done!
    task_5 is done!

    从返回的结果看,主线程在执行完executor.submit(new CallabelTask("task_"+(++i))) 之后并没有阻塞,而是继续往下执行println语句打印出语句:

    All the tasks have been submited through invokeAll method!

    而提交的任务将由其他线程在“将来某个时刻“去执行。当然在主线程去获取执行结果f.get() 的时候肯定是要阻塞的,因为既然要获取结果了,当然要等到任务执行完毕返回才有啊!

    如果把上面的CallabelTask改变成RunnableTask,则返回的结果将是null,原因是提交的时候在new TaskFor方法中就已经指定了返回结果为null,就是上面的submit源代码中的这句话:

    RunnableFuture<Object> ftask = newTaskFor(task, null);

    测试的代码是:

    class RunnableTask implements Runnable{
            String name;
            public RunnableTask(String name){
                this.name = name;
            }
            @Override
            public void run() {
                System.out.println("Start to execute the task " + name);
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    //RunnableTask 执行结果:
    All the tasks have been submited through invokeAll method!
    Start to execute the task task_1
    Start to execute the task task_5
    Start to execute the task task_3
    Start to execute the task task_4
    Start to execute the task task_2
    null
    null
    null
    null
    null
  • 相关阅读:
    杜马岛
    Type interface com.zhaoka.mapper.DatKcardKmMapper is not known to the MapperRegistry
    jsp实现自动登录
    Struts2中的get、set方法重要性 .
    struts2 通过前台标签name属性将值传到后台,没有name属性传值,则后台对象有默认值,不为null。
    Jsp 操作 Cookie 实现自动登录
    struts2的bean类名首字母和第二个字母都不能大写
    mybatis自动生成的ExamMapper.xml方法总结
    Mybatis插入时注意,没有主键值。所以主键一般为自增类型
    <ywaf:code code="${project.projectType}" typeCode="PROJECT_TYPE"/>
  • 原文地址:https://www.cnblogs.com/zhailzh/p/3972917.html
Copyright © 2011-2022 走看看