zoukankan      html  css  js  c++  java
  • Java 使用new Thread和线程池的区别

    本文转至:https://www.cnblogs.com/cnmenglang/p/6273761.html , 孟凡柱的专栏 的博客,在此谢谢博主!

    1.new Thread的弊端
    执行一个异步任务你还只是如下new Thread吗

    new Thread(new Runnable() {
      
        @Override
        public void run() {
            // TODO Auto-generated method stub
        }
    }).start();

     说说弊端:

    a. 每次new Thread新建对象性能差。
    b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
    c. 缺乏更多功能,如定时执行、定期执行、线程中断。
    相比new Thread,Java提供的四种线程池的好处在于:
    a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
    b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
    c. 提供定时执行、定期执行、单线程、并发数控制等功能。

    2.Executors提供四种线程池

    newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。线程池的规模不存在限制。
    newFixedThreadPool 创建一个固定长度线程池,可控制线程最大并发数,超出的线程会在队列中等待。
    newScheduledThreadPool 创建一个固定长度线程池,支持定时及周期性任务执行。
    newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

     下面代码说明:

    (1). newCachedThreadPool
    创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。示例代码如下:

    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; i++) {
        final int index = i;
        try {
            Thread.sleep(index * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
      
        cachedThreadPool.execute(new Runnable() {
      
            @Override
            public void run() {
                System.out.println(index);
            }
        });
    }

     线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。

    (2). newFixedThreadPool
    创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。示例代码如下:

    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 10; i++) {
        final int index = i;
        fixedThreadPool.execute(new Runnable() {
      
            @Override
            public void run() {
                try {
                    System.out.println(index);
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
    }

    因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。

    定长线程池的大小最好根据系统资源进行设置。

    (3) newScheduledThreadPool
    创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:

    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    scheduledThreadPool.schedule(new Runnable() {
      
        @Override
        public void run() {
            System.out.println("delay 3 seconds");
        }
    }, 3, TimeUnit.SECONDS);

     表示延迟3秒执行。

    定期执行示例代码如下:

    scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
      
        @Override
        public void run() {
            System.out.println("delay 1 seconds, and excute every 3 seconds");
        }
    }, 1, 3, TimeUnit.SECONDS);

    表示延迟1秒后每3秒执行一次。

    ScheduledExecutorService比Timer更安全,功能更强大。

    (4)、newSingleThreadExecutor
    创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下:

    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 10; i++) {
        final int index = i;
        singleThreadExecutor.execute(new Runnable() {
      
            @Override
            public void run() {
                try {
                    System.out.println(index);
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
    }

     结果依次输出,相当于顺序执行各个任务。

    2.ExecutorService中submit和execute的区别

    以下这是submit 的源码:

    public abstract class AbstractExecutorService implements ExecutorService {
        
        protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
            return new FutureTask<T>(runnable, value);
        }
    
        protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
            return new FutureTask<T>(callable);
        }
    
        public Future<?> submit(Runnable task) {
            if (task == null) throw new NullPointerException();
            RunnableFuture<Void> 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最终返回的是FutureTask对象,而execute:

    public interface Executor {
        
        void execute(Runnable command);
    }

    具体的实现在ThreadPoolExecutor类中

     public void execute(Runnable command) {
            if (command == null)
                throw new NullPointerException();
     
            int c = ctl.get();
            if (workerCountOf(c) < corePoolSize) {
                if (addWorker(command, true))
                    return;
                c = ctl.get();
            }
            if (isRunning(c) && workQueue.offer(command)) {
                int recheck = ctl.get();
                if (! isRunning(recheck) && remove(command))
                    reject(command);
                else if (workerCountOf(recheck) == 0)
                    addWorker(null, false);
            }
            else if (!addWorker(command, false))
                reject(command);
        }

    所以,submit内部调用execute,且submit有返回值,方便exception处理。

    submit Demo:

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    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;
    
    public class Main {
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newCachedThreadPool();
            List<Future<String>> resultList = new ArrayList<Future<String>>();
    
            // 创建10个任务并执行
            for (int i = 0; i < 10; i++) {
                // 使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中
                Future<String> future = executorService.submit(new TaskWithResult(i));
                // 将任务执行结果存储到List中
                resultList.add(future);
            }
            executorService.shutdown();
    
            // 遍历任务的结果
            for (Future<String> fs : resultList) {
                try {
                    System.out.println(fs.get()); // 打印各个线程(任务)执行的结果
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    executorService.shutdownNow();
                    e.printStackTrace();
                    return;
                }
            }
        }
    }
    class TaskWithResult implements Callable<String> {
        private int id;
    
        public TaskWithResult(int id) {
            this.id = id;
        }
    
        /**
         * 任务的具体过程,一旦任务传给ExecutorService的submit方法,则该方法自动在一个线程上执行。
         *
         * @return
         * @throws Exception
         */
        public String call() throws Exception {
            System.out.println("call()方法被自动调用,干活!!!             " + Thread.currentThread().getName());
            if (new Random().nextBoolean())
                throw new TaskException("Meet error in task." + Thread.currentThread().getName());
            // 一个模拟耗时的操作
            for (int i =9; i > 0; i--)
                ;
            return "call()方法被自动调用,任务的结果是:" + id + "    " + Thread.currentThread().getName();
        }
    }
    
    class TaskException extends Exception {
        public TaskException(String message) {
            super(message);
        }
    }

    Runnable和Callable的区别是,
    (1)Callable规定的方法是call(),Runnable规定的方法是run().
    (2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得
    (3)call方法可以抛出异常,run方法不可以
    (4)运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。

  • 相关阅读:
    设计模式:备忘录模式(Memento)
    设计模式:中介者模式(Mediator)
    设计模式:迭代器模式(Iterator)
    设计模式:解释器模式(Interpreter)
    设计模式:命令模式(Command)
    设计模式:职责链模式(Chain of Responsibility)
    设计模式:单例模式(单例模式)
    win7硬盘安装方法
    sqlite 附加和分离数据库
    Sqlite 复制表结构和数据
  • 原文地址:https://www.cnblogs.com/qffxj/p/10136785.html
Copyright © 2011-2022 走看看