精华内容
下载资源
问答
  • java线程池场景使用

    千次阅读 2019-03-21 16:43:56
    当服务器接口之间通讯中,如果A服务器请求B服务器,只返回请求通讯成功且不需要实时返回业务成功或失败时,处理成功或者失败用异步通知方式,那么可以采用线程池或者消息队列业务场景:金融业务中强风控,还款等等...

    当服务器接口之间通讯中,如果A服务器请求B服务器,只返回请求通讯成功且不需要实时返回业务成功或失败时,处理成功或者失败用异步通知方式,那么可以采用线程池或者消息队列
    业务场景:金融业务中的强风控,还款等等
    重点:如果需要同步通知业务成功或失败,让A服务器提供通知接口,在服务器B线程中可以同步通知服务器A中的接口   累计金融业务弱风控 

    代码如下:

    /**
     * @author stone
     * @date 2019-03-21 16:20:21
     */
    @Service
    public class ExceutorTestServiceImpl implements ExceutorTestService{
    
        @Resource
        SlUserMapper slUserMapper;
    
        private ExecutorService executorService = Executors.newFixedThreadPool(5);
    
        Logger logger = LoggerFactory.getLogger(ExceutorTestServiceImpl.class);
    
        @Override
        public void exceutorTest() {
            logger.info("部分业务有线程来处理,无需返回结果,可以拋出异常全局捕获即可");
            SubmitStrongRiskTask task = new SubmitStrongRiskTask(1l, BigDecimal.valueOf(10l));
            executorService.execute(task);
            logger.info("继续做其他业务");
        }
    
        class SubmitStrongRiskTask implements Runnable {
            private Long userId;
            private BigDecimal amount;
    
            SubmitStrongRiskTask(Long userId, BigDecimal amount) {
                this.userId = userId;
                this.amount = amount;
            }
    
            @Override
            public void run() {
                SlUser slUser = slUserMapper.getUserById(16l);
                logger.info("用户手机号码是:"+ slUser.getMobile());
            }
        }
    
    }
    
    打印日志如下:
    192.168.3.78 部分业务有线程来处理,无需返回结果,可以拋出异常全局捕获即可
    192.168.3.78 继续做其他业务
    192.168.3.78 用户手机号码是:15576602451
    
    
    展开全文
  • 如果避免线程池出现OOM?Runnable和Callable的区别是什么...本文将对这些问题一一解答,同时还将给出使用线程池的常见场景和代码片段。基础知识1、Executors创建线程池Java中创建线程池很简单,只需要调用Executors...
    c5b97e56f6a1e97dc3eccd54bd5a5868.png
    来源:CarpenterLeewww.cnblogs.com/CarpenterLee/p/9558026.html
    构造一个线程池为什么需要几个参数?如果避免线程池出现OOM?Runnable和Callable的区别是什么?本文将对这些问题一一解答,同时还将给出使用线程池的常见场景和代码片段。基础知识1、Executors创建线程池Java中创建线程池很简单,只需要调用Executors中相应的便捷方法即可。比如:
    • Executors
    • newFixedThreadPool(int nThreads)
    但是便捷不仅隐藏了复杂性,也为我们埋下了潜在的隐患(OOM,线程耗尽)。2、Executors创建线程池便捷方法列表60b7a9d8a7b9f380b226f04b3270f2b8.png小程序使用这些快捷方法没什么问题,对于服务端需要长期运行的程序,创建线程池应该直接使用ThreadPoolExecutor的构造方法。没错,上述Executors方法创建的线程池就是ThreadPoolExecutor。3、ThreadPoolExecutor构造方法Executors中创建线程池的快捷方法;实际上是调用了ThreadPoolExecutor的构造方法(定时任务使用的是ScheduledThreadPoolExecutor)该类构造方法参数列表如下:
    // Java线程池的完整构造函数public ThreadPoolExecutor(  int corePoolSize, // 线程池长期维持的线程数,即使线程处于Idle状态,也不会回收。  int maximumPoolSize, // 线程数的上限  long keepAliveTime, TimeUnit unit, // 超过corePoolSize的线程的idle时长,                                     // 超过这个时间,多余的线程会被回收。  BlockingQueue workQueue, // 任务的排队队列  ThreadFactory threadFactory, // 新线程的产生方式  RejectedExecutionHandler handler) // 拒绝策略
    竟然有7个参数,很无奈,构造一个线程池确实需要这么多参数。这些参数中,比较容易引起问题的有:corePoolSize, maximumPoolSize, workQueue以及handler:
    1、corePoolSize和maximumPoolSize设置不当会影响效率,甚至耗尽线程; 2、workQueue设置不当容易导致OOM; 3、handler设置不当会导致提交任务时抛出异常。
    正确的参数设置方式会在下文给出。4、线程池的工作顺序
    If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing.If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread.If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.
    corePoolSize -> 任务队列 -> maximumPoolSize -> 拒绝策略5、Runnable和Callable可以向线程池提交的任务有两种:Runnable和Callable,二者的区别如下:
    1. 方法签名不同,void Runnable.run(), V Callable.call() throws Exception
    2. 是否允许有返回值,Callable允许有返回值
    3. 是否允许抛出异常,Callable允许抛出异常。
    Callable是JDK1.5时加入的接口,作为Runnable的一种补充,允许有返回值,允许抛出异常。三种提交任务的方式:b35460fa14ec8b8bd183f51812224838.png如何正确使用线程池1、避免使用无界队列不要使用Executors.newXXXThreadPool()快捷方法创建线程池。因为这种方式会使用无界的任务队列,为避免OOM,我们应该使用ThreadPoolExecutor的构造方法手动指定队列的最大长度:
    ExecutorService executorService = new ThreadPoolExecutor(2, 2,                 0, TimeUnit.SECONDS,                 new ArrayBlockingQueue<>(512), // 使用有界队列,避免OOM                new ThreadPoolExecutor.DiscardPolicy());
    2、明确拒绝任务时的行为任务队列总有占满的时候,这时再submit()提交新的任务会怎么样呢?RejectedExecutionHandler接口为我们提供了控制方式,接口定义如下:
    public interface RejectedExecutionHandler {    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);}
    线程池给我们提供了几种常见的拒绝策略:9d51c71925381832bcd872e93867d7f8.pnge50415b6ecb1623e0eb56158c924eb09.png线程池默认的拒绝行为是AbortPolicy也就是抛出RejectedExecutionHandler异常,该异常是非受检异常,很容易忘记捕获。如果不关心任务被拒绝的事件,可以将拒绝策略设置成DiscardPolicy,这样多余的任务会悄悄的被忽略。
    ExecutorService executorService = new ThreadPoolExecutor(2, 2,                 0, TimeUnit.SECONDS,                 new ArrayBlockingQueue<>(512),                 new ThreadPoolExecutor.DiscardPolicy());// 指定拒绝策略
    3、获取处理结果和异常线程池的处理结果、以及处理过程中的异常都被包装到Future中。并在调用Future.get()方法时获取,执行过程中的异常会被包装成ExecutionException,submit()方法本身不会传递结果和任务执行过程中的异常。获取执行结果的代码可以这样写:
    ExecutorService executorService = Executors.newFixedThreadPool(4);Future future = executorService.submit(new Callable() {        @Override        public Object call() throws Exception {            throw new RuntimeException("exception in call~");// 该异常会在调用Future.get()时传递给调用者        }    });try {  Object result = future.get();} catch (InterruptedException e) {  // interrupt} catch (ExecutionException e) {  // exception in Callable.call()  e.printStackTrace();}
    上述代码输出类似如下:3588d6101d7144e6b6860765238ff520.png线程池的常用场景1、正确构造线程池
    int poolSize = Runtime.getRuntime().availableProcessors() * 2;BlockingQueue queue = new ArrayBlockingQueue<>(512);RejectedExecutionHandler policy = new ThreadPoolExecutor.DiscardPolicy();executorService = new ThreadPoolExecutor(poolSize, poolSize,    0, TimeUnit.SECONDS,            queue,            policy);
    2、获取单个结果过submit()向线程池提交任务后会返回一个Future,调用V Future.get()方法能够阻塞等待执行结果,V get(long timeout, TimeUnit unit)方法可以指定等待的超时时间。3、获取多个结果如果向线程池提交了多个任务,要获取这些任务的执行结果,可以依次调用Future.get()获得。但对于这种场景,我们更应该使用ExecutorCompletionService,该类的take()方法总是阻塞等待某一个任务完成,然后返回该任务的Future对象。向CompletionService批量提交任务后,只需调用相同次数的CompletionService.take()方法,就能获取所有任务的执行结果,获取顺序是任意的,取决于任务的完成顺序:
    void solve(Executor executor, Collection> solvers)   throws InterruptedException, ExecutionException {   CompletionService ecs = new ExecutorCompletionService(executor);// 构造器   for (Callable s : solvers)// 提交所有任务       ecs.submit(s);   int n = solvers.size();   for (int i = 0; i < n; ++i) {// 获取每一个完成的任务       Result r = ecs.take().get();       if (r != null)           use(r);   }}
    4、单个任务的超时时间V Future.get(long timeout, TimeUnit unit)方法可以指定等待的超时时间,超时未完成会抛出TimeoutException。5、多个任务的超时时间等待多个任务完成,并设置最大等待时间,可以通过CountDownLatch完成:
    public void testLatch(ExecutorService executorService, List tasks)     throws InterruptedException{    CountDownLatch latch = new CountDownLatch(tasks.size());      for(Runnable r : tasks){          executorService.submit(new Runnable() {              @Override              public void run() {                  try{                      r.run();                  }finally {                      latch.countDown();// countDown                  }              }          });      }      latch.await(10, TimeUnit.SECONDS); // 指定超时时间  }

    线程池和装修公司

    以运营一家装修公司做个比喻。公司在办公地点等待客户来提交装修请求;公司有固定数量的正式工以维持运转;旺季业务较多时,新来的客户请求会被排期,比如接单后告诉用户一个月后才能开始装修;当排期太多时,为避免用户等太久,公司会通过某些渠道(比如人才市场、熟人介绍等)雇佣一些临时工(注意,招聘临时工是在排期排满之后);如果临时工也忙不过来,公司将决定不再接收新的客户,直接拒单。线程池就是程序中的“装修公司”,代劳各种脏活累活。上面的过程对应到线程池上:
    // Java线程池的完整构造函数public ThreadPoolExecutor(  int corePoolSize, // 正式工数量  int maximumPoolSize, // 工人数量上限,包括正式工和临时工  long keepAliveTime, TimeUnit unit, // 临时工游手好闲的最长时间,超过这个时间将被解雇  BlockingQueue workQueue, // 排期队列  ThreadFactory threadFactory, // 招人渠道  RejectedExecutionHandler handler) // 拒单方式
    总结:
    1. Executors为我们提供了构造线程池的便捷方法,对于服务器程序我们应该杜绝使用这些便捷方法,而是直接使用线程池ThreadPoolExecutor的构造方法,避免无界队列可能导致的OOM以及线程个数限制不当导致的线程数耗尽等问题。
    2. ExecutorCompletionService提供了等待所有任务执行结束的有效方式,如果要设置等待的超时时间,则可以通过CountDownLatch完成。
    946f1240df9452399ba4d933bca547f8.png往期精选:30个公认架构原则!260+道Java面试真题汇总开挂进阶Java架构师?这份超强清单了解一下84795552a2c57d1ee6fc1f0dcf1b78a8.png
    展开全文
  • 一、如下方式存在的问题newThread(){@Overridepublicvoidrun(){//业务逻辑}}.start();1、首先频繁的创建、销毁对象是一个很消耗性能的事情;...二、使用线程池有什么优点1、线程池中线程的使用率提升,减少对象的...

    897b8fab5a16af7e56e8fc603d80b77a.png

    一、如下方式存在的问题

    new Thread() {

    @Override

    publicvoid run() {

    // 业务逻辑

    }

    }.start();

    1、首先频繁的创建、销毁对象是一个很消耗性能的事情;2、如果用户量比较大,导致占用过多的资源,可能会导致我们的服务由于资源不足而宕机;3、综上所述,在实际的开发中,这种操作其实是不可取的一种方式。

    二、使用线程池有什么优点

    1、线程池中线程的使用率提升,减少对象的创建、销毁;2、线程池可以控制线程数,有效的提升服务器的使用资源,避免由于资源不足而发生宕机等问题;

    三、线程池的四种使用方式

    1、newCachedThreadPool

    创建一个线程池,如果线程池中的线程数量过大,它可以有效的回收多余的线程,如果线程数不足,那么它可以创建新的线程。

    publicstaticvoid method() throws Exception {

    ExecutorService executor = Executors.newCachedThreadPool();

    for(inti = 0; i 

    final intindex= i;

    Thread.sleep(1000);

    executor.execute(new Runnable() {

    @Override

    publicvoid run() {

    System.out.println(Thread.currentThread().getName() +"  "+index);

    }

    });

    }

    }

    执行结果

    902d03a0e07e179d48b6aa902364f671.png

    通过分析我看可以看到,至始至终都由一个线程执行,实现了线程的复用,并没有创建多余的线程。如果当我们的业务需要一定的时间进行处理,那么将会出现什么结果。我们来模拟一下。

    8fd81668a2f4e088d111dc9a45f90799.gif

    可以明显的看出,现在就需要几条线程来交替执行。

    不足:这种方式虽然可以根据业务场景自动的扩展线程数来处理我们的业务,但是最多需要多少个线程同时处理缺是我们无法控制的;

    优点:如果当第二个任务开始,第一个任务已经执行结束,那么第二个任务会复用第一个任务创建的线程,并不会重新创建新的线程,提高了线程的复用率;

    2、newFixedThreadPool

    这种方式可以指定线程池中的线程数。举个栗子,如果一间澡堂子最大只能容纳20个人同时洗澡,那么后面来的人只能在外面排队等待。如果硬往里冲,那么只会出现一种情景,摩擦摩擦...

    首先测试一下最大容量为一个线程,那么会不会是我们预测的结果。

    publicstaticvoid method_01() throws InterruptedException {

    ExecutorService executor = Executors.newFixedThreadPool(1);

    for(inti = 0; i 

    Thread.sleep(1000);

    final intindex= i;

    executor.execute(() -> {

    try {

    Thread.sleep(2 * 1000);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    System.out.println(Thread.currentThread().getName() +"  "+index);

    });

    }

    executor.shutdown();

    }

    执行结果

    36bc8c616a254b44d99f94bed3b3b5da.gif

    我们改为3条线程再来看下结果

    c75968cecf717692facbeb6277803e4e.gif

    优点:两个结果综合说明,newFixedThreadPool的线程数是可以进行控制的,因此我们可以通过控制最大线程来使我们的服务器打到最大的使用率,同事又可以保证及时流量突然增大也不会占用服务器过多的资源。

    3、newScheduledThreadPool

    该线程池支持定时,以及周期性的任务执行,我们可以延迟任务的执行时间,也可以设置一个周期性的时间让任务重复执行。 该线程池中有以下两种延迟的方法。

    scheduleAtFixedRate

    测试一

    publicstaticvoid method_02() {

    ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);

    executor.scheduleAtFixedRate(new Runnable() {

    @Override

    publicvoid run() {

    long start = new Date().getTime();

    System.out.println("scheduleAtFixedRate 开始执行时间:"+

    DateFormat.getTimeInstance().format(new Date()));

    try {

    Thread.sleep(5000);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    long end= newDate().getTime();

    System.out.println("scheduleAtFixedRate 执行花费时间="+ (end- start) / 1000 +"m");

    System.out.println("scheduleAtFixedRate 执行完成时间:"+ DateFormat.getTimeInstance().format(newDate()));

    System.out.println("======================================");

    }

    }, 1, 5, TimeUnit.SECONDS);

    }

    执行结果

    e89ac9c3fcda349f3eebef9cdbe07fab.gif

    测试二

    c783aa09de9ee2a5ebb0f5bd9ff02279.gif

    总结:以上两种方式不同的地方是任务的执行时间,如果间隔时间大于任务的执行时间,任务不受执行时间的影响。如果间隔时间小于任务的执行时间,那么任务执行结束之后,会立马执行,至此间隔时间就会被打乱。

    scheduleWithFixedDelay

    测试一

    publicstaticvoid method_03() {

    ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

    executor.scheduleWithFixedDelay(new Runnable() {

    @Override

    publicvoid run() {

    long start = new Date().getTime();

    System.out.println("scheduleWithFixedDelay 开始执行时间:"+

    DateFormat.getTimeInstance().format(new Date()));

    try {

    Thread.sleep(1000);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    long end= newDate().getTime();

    System.out.println("scheduleWithFixedDelay执行花费时间="+ (end- start) / 1000 +"m");

    System.out.println("scheduleWithFixedDelay执行完成时间:"

    + DateFormat.getTimeInstance().format(new Date()));

    System.out.println("======================================");

    }

    }, 1, 2, TimeUnit.SECONDS);

    }

    执行结果

    14c306af684c6c4b499af648cb741a10.gif

    测试二

    publicstaticvoid method_03() {

    ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

    executor.scheduleWithFixedDelay(new Runnable() {

    @Override

    publicvoid run() {

    long start = new Date().getTime();

    System.out.println("scheduleWithFixedDelay 开始执行时间:"+

    DateFormat.getTimeInstance().format(new Date()));

    try {

    Thread.sleep(5000);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    long end= newDate().getTime();

    System.out.println("scheduleWithFixedDelay执行花费时间="+ (end- start) / 1000 +"m");

    System.out.println("scheduleWithFixedDelay执行完成时间:"

    + DateFormat.getTimeInstance().format(new Date()));

    System.out.println("======================================");

    }

    }, 1, 2, TimeUnit.SECONDS);

    }

    执行结果

    501e17b8446135db451beb87f4571eea.gif

    总结:同样的,跟scheduleWithFixedDelay测试方法一样,可以测出scheduleWithFixedDelay的间隔时间不会受任务执行时间长短的影响。

    4、newSingleThreadExecutor

    这是一个单线程池,至始至终都由一个线程来执行。

    publicstaticvoid method_04() {

    ExecutorService executor = Executors.newSingleThreadExecutor();

    for(inti = 0; i 

    final intindex= i;

    executor.execute(() -> {

    try {

    Thread.sleep(2 * 1000);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    System.out.println(Thread.currentThread().getName() +"   "+index);

    });

    }

    executor.shutdown();

    }

    执行结果

    b8be2d1eb6d678cc599c1586d6b5e92d.gif

    四、线程池的作用

    线程池的作用主要是为了提升系统的性能以及使用率。文章刚开始就提到,如果我们使用最简单的方式创建线程,如果用户量比较大,那么就会产生很多创建和销毁线程的动作,这会导致服务器在创建和销毁线程上消耗的性能可能要比处理实际业务花费的时间和性能更多。线程池就是为了解决这种这种问题而出现的。

    同样思想的设计还有很多,比如数据库连接池,由于频繁的连接数据库,然而创建连接是一个很消耗性能的事情,所有数据库连接池就出现了。

    【编辑推荐】

    【责任编辑:武晓燕 TEL:(010)68476606】

    点赞 0

    展开全文
  • 一、如下方式存在问题new Thread() { @Override public void run() { // 业务逻辑 }}.start(); 1、首先频繁创建、销毁对象是一个很消耗性能事情;2、如果用户量比较大,导致占用过多...二、使用线程池有什么...

    一、如下方式存在的问题

    new Thread() {    @Override    public void run() {        // 业务逻辑    }}.start();
    

    1、首先频繁的创建、销毁对象是一个很消耗性能的事情;2、如果用户量比较大,导致占用过多的资源,可能会导致我们的服务由于资源不足而宕机;3、综上所述,在实际的开发中,这种操作其实是不可取的一种方式。

    二、使用线程池有什么优点

    1、线程池中线程的使用率提升,减少对象的创建、销毁;2、线程池可以控制线程数,有效的提升服务器的使用资源,避免由于资源不足而发生宕机等问题;

    三、线程池的四种使用方式

    1、newCachedThreadPool

    创建一个线程池,如果线程池中的线程数量过大,它可以有效的回收多余的线程,如果线程数不足,那么它可以创建新的线程。

    public static void method() throws Exception {    ExecutorService executor = Executors.newCachedThreadPool();    for (int i = 0; i < 5; i++) {        final int index = i;        Thread.sleep(1000);        executor.execute(new Runnable() {            @Override            public void run() {                System.out.println(Thread.currentThread().getName() + "  " + index);            }        });    }}
    

    执行结果

    2ac603c351b41ac48981db332d3ba6f6.png

    通过分析我看可以看到,至始至终都由一个线程执行,实现了线程的复用,并没有创建多余的线程。如果当我们的业务需要一定的时间进行处理,那么将会出现什么结果。我们来模拟一下。

    9ffc805a179b58ea9e50bb11aa46b8aa.gif

    可以明显的看出,现在就需要几条线程来交替执行。

    不足:这种方式虽然可以根据业务场景自动的扩展线程数来处理我们的业务,但是最多需要多少个线程同时处理缺是我们无法控制的;

    优点:如果当第二个任务开始,第一个任务已经执行结束,那么第二个任务会复用第一个任务创建的线程,并不会重新创建新的线程,提高了线程的复用率;

    2、newFixedThreadPool

    这种方式可以指定线程池中的线程数。举个栗子,如果一间澡堂子最大只能容纳20个人同时洗澡,那么后面来的人只能在外面排队等待。如果硬往里冲,那么只会出现一种情景,摩擦摩擦...

    首先测试一下最大容量为一个线程,那么会不会是我们预测的结果。

    public static void method_01() throws InterruptedException {    ExecutorService executor = Executors.newFixedThreadPool(1);    for (int i = 0; i < 10; i++) {        Thread.sleep(1000);        final int index = i;        executor.execute(() -> {            try {                Thread.sleep(2 * 1000);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName() + "  " + index);        });    }    executor.shutdown();}
    

    执行结果

    81968030c1a581d78993c7aa1f74d16f.gif

    我们改为3条线程再来看下结果

    e7bf03b0eb0fdd3d81e81f3212ef19a2.gif

    优点:两个结果综合说明,newFixedThreadPool的线程数是可以进行控制的,因此我们可以通过控制最大线程来使我们的服务器打到最大的使用率,同事又可以保证及时流量突然增大也不会占用服务器过多的资源。

    3、newScheduledThreadPool

    该线程池支持定时,以及周期性的任务执行,我们可以延迟任务的执行时间,也可以设置一个周期性的时间让任务重复执行。 该线程池中有以下两种延迟的方法。

    • scheduleAtFixedRate

    测试一

    public static void method_02() {    ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);    executor.scheduleAtFixedRate(new Runnable() {        @Override        public void run() {            long start = new Date().getTime();            System.out.println("scheduleAtFixedRate 开始执行时间:" +                    DateFormat.getTimeInstance().format(new Date()));            try {                Thread.sleep(5000);            } catch (InterruptedException e) {                e.printStackTrace();            }            long end = new Date().getTime();            System.out.println("scheduleAtFixedRate 执行花费时间=" + (end - start) / 1000 + "m");            System.out.println("scheduleAtFixedRate 执行完成时间:" + DateFormat.getTimeInstance().format(new Date()));            System.out.println("======================================");        }    }, 1, 5, TimeUnit.SECONDS);}
    

    执行结果

    8e9675d2f15ee8e15d3baf52af92c252.gif

    测试二

    bfa08a0e096cea4830ac25ff8e070fb6.gif

    总结:以上两种方式不同的地方是任务的执行时间,如果间隔时间大于任务的执行时间,任务不受执行时间的影响。如果间隔时间小于任务的执行时间,那么任务执行结束之后,会立马执行,至此间隔时间就会被打乱。

    • scheduleWithFixedDelay

    测试一

    public static void method_03() {    ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);    executor.scheduleWithFixedDelay(new Runnable() {        @Override        public void run() {            long start = new Date().getTime();            System.out.println("scheduleWithFixedDelay 开始执行时间:" +                    DateFormat.getTimeInstance().format(new Date()));            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }            long end = new Date().getTime();            System.out.println("scheduleWithFixedDelay执行花费时间=" + (end - start) / 1000 + "m");            System.out.println("scheduleWithFixedDelay执行完成时间:"                    + DateFormat.getTimeInstance().format(new Date()));            System.out.println("======================================");        }    }, 1, 2, TimeUnit.SECONDS);}
    

    执行结果

    bc35e0fd322a581ff5a4a0556a41f8a8.gif

    测试二

    public static void method_03() {    ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);    executor.scheduleWithFixedDelay(new Runnable() {        @Override        public void run() {            long start = new Date().getTime();            System.out.println("scheduleWithFixedDelay 开始执行时间:" +                    DateFormat.getTimeInstance().format(new Date()));            try {                Thread.sleep(5000);            } catch (InterruptedException e) {                e.printStackTrace();            }            long end = new Date().getTime();            System.out.println("scheduleWithFixedDelay执行花费时间=" + (end - start) / 1000 + "m");            System.out.println("scheduleWithFixedDelay执行完成时间:"                    + DateFormat.getTimeInstance().format(new Date()));            System.out.println("======================================");        }    }, 1, 2, TimeUnit.SECONDS);}
    

    执行结果

    a22c669affb34f9b20893e19fc720139.gif

    总结:同样的,跟scheduleWithFixedDelay测试方法一样,可以测出scheduleWithFixedDelay的间隔时间不会受任务执行时间长短的影响。

    4、newSingleThreadExecutor

    这是一个单线程池,至始至终都由一个线程来执行。

    public static void method_04() {    ExecutorService executor = Executors.newSingleThreadExecutor();    for (int i = 0; i < 5; i++) {        final int index = i;        executor.execute(() -> {            try {                Thread.sleep(2 * 1000);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName() + "   " + index);        });    }    executor.shutdown();}
    

    执行结果

    c7a69545af7859576913ccec1e3fc8d5.gif

    四、线程池的作用

    线程池的作用主要是为了提升系统的性能以及使用率。文章刚开始就提到,如果我们使用最简单的方式创建线程,如果用户量比较大,那么就会产生很多创建和销毁线程的动作,这会导致服务器在创建和销毁线程上消耗的性能可能要比处理实际业务花费的时间和性能更多。线程池就是为了解决这种这种问题而出现的。

    同样思想的设计还有很多,比如数据库连接池,由于频繁的连接数据库,然而创建连接是一个很消耗性能的事情,所有数据库连接池就出现了。

    展开全文
  • 1、诸如 Web服务器、数据库服务器、文件服务器或邮件服务器之类许多服务器应用程序都面向处理来自某些远程来源大量短小任务。请求以某种方式到达服务器,这种方式可能是通过网络协议(例如 HTTP、FTP 或 POP)、...
  • Java的线程池  workQueue参数分析 handler参数分析 execute方法与submit方法 合理选择线程池大小 为什么要使用线程池? 对于java初学者来说,首先接触到创建线程方法就是new Thread,或者实现...
  • 单个线程使用完随即被销毁,如果在list中频繁创建、销毁线程,会给服务器带来不小性能开支,所有使用线程池将线程创建、销毁工作统一处理,最后销毁,以此来提高效率 。 //普通创建线程方式一 new Thread(() -&...
  • Java线程池的四种用法与使用场景

    千次阅读 2019-10-24 22:54:08
    文章目录Java线程池的四种用法与使用场景一、如下方式存在的问题二、使用线程池有什么优点三、线程池的四种使用方式1、newCachedThreadPool2、newFixedThreadPool3、newScheduledThreadPool4、... ...
  • java模拟秒杀,网络限流的场景java代码实现,使用java线程池操作模拟场景 运行效果如下 没有限流,执行正常业务 没有限流,执行正常业务 没有限流,执行正常业务 没有限流,执行正常业务 没有限流,执行正常...
  • Java线程池的使用

    2018-10-21 23:28:38
    概述:在一些场景下,我们使用多线程去解决一些高并发问题,实现起来很方便。但是会有一些问题,如果并发线程数量很多,并且每个线程都是执行一个时间很短任务就结束了,这样频繁创建线程就会大大降低系统...
  • 常用线程池使用场景

    千次阅读 2019-01-15 21:05:38
    java线程池: Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 newFixedThreadPool 创建一个定长...
  • Java线程池的使用总结

    2017-05-09 22:04:27
    Java的线程池是运用场景最多并发框架, 几乎所有需要异步或并发执行任务程序都可以使用线程池。 在开发过程中, 合理地使用线程池能够带来3个好处。  第一: 降低资源消耗。 通过重复利用已创建线程降低...
  • 1、线程池的使用场景 等待返回任务的结果的多步骤的处理场景, 批量并发执行任务,总耗时是单个步骤耗时最长的那个,提供整体的执行效率, 最终一致性,异步执行任务,无需等待,快速返回 2、线程池的关键...
  • java线程池的几种使用方式和场景

    千次阅读 2018-03-08 18:50:18
    一、线程池使用场景单个任务处理时间短将需处理的任务数量大二、使用Java线程池好处1.使用new Thread()创建线程的弊端:每次通过...2.使用Java线程池的好处:重用存在的线程,减少对象创建、消亡的开销,提升性能。...
  • 原标题:Java线程池的四种用法与使用场景一、如下方式存在的问题newThread {@Overridepublicvoidrun{// 业务逻辑}}.start;1、首先频繁的创建、销毁对象是一个很消耗性能的事情;2、如果用户量比较大,导致占用过多的...
  • 目录 一、四种线程池 ...二、使用场景详解 2.1、newCachedThreadPool: 2.2、newFixedThreadPool 2.3、newSingleThreadExecutor 2.4、NewScheduledThreadPool 三、线程池任务执行流程 四、备注 一...
  • 、为什么要用线程池? 诸如 Web 服务器、数据库服务器、文件服务器或邮件服务器之类许多服务器应用程序都面向处理来自某些远程来源大量短小任务。请求以某种方式到达服务器,这种方 式可能是通过网络协议...
  • 来源公众号一个程序员成长 ,作者小涛一、如下方式存在问题new Thread() { @Override public void run() { // 业务逻辑 }}.start();1、首先频繁创建、销毁对象是一个很消耗性能事情;...二、使用线程池有...
  • 1 线程池的好处 线程的创建和销毁由线程池维护,一个线程在完成任务后并不会立即销毁,而是由后续的任务复用这个线程,从而减少线程的创建和销毁,节约系统的开销。 线程池旨在线程的复用,这就可以节约我们用以往...
  • 最近我们组杨青同学遇到一个使用线程池不当的问题:异步...从这个问题中,我们学到了两点:线程池的使用,需要充分分析业务场景后作出选择,必要的情况下需要自定义线程池;线程池的运行状况,也需要监控关于线程...
  • Java线程池场景化总结

    2020-08-26 19:35:10
    Java线程池场景化总结 本文将通过不同的场景,对多线程及线程池使用建议进行介绍,以下场景示例将以8核心CPU为例 1)任务数多但资源占用不大 场景解读:电商平台消息推送或短信通知,发邮件、对于该场景来说需要...
  • 我们一般不会选择直接使用线程类Thread进行多线程编程,而是使用更方便的线程池来进行任务调度和管理。线程池就像共享单车,我们只要在我们有需要时候去获取就可以了。甚至可以说线程池更棒,我们只需要把任务...
  • 文章开始先给大家一点福利:图片我老婆镇楼书籍、Java进阶路线、面试题,PDF文档资料。​shimo.im一、如下方式存在问题new Thread() { @Override public void run() { // 业务逻辑 } }.start();1、首先频繁...
  • java 线程池 java 提供了四种线程池 : newCachedThreadPool newFixedThreadPool newScheduledThreadPool newSingleThreadExecutor
  • # 如下方式存在问题new Thread() { @Override public void run() { // 业务逻辑 }}.start(); 1、首先频繁创建、销毁对象是一个很消耗性能事情; 2、如果用户量比较大,导致占用过多...# 使用线程池...
  • 线程池是一个稀缺资源,如果被无限的创建,会消耗系统资源,产生竞争死锁,降低系统效率。...线程池的优势: 重用线程,减少线程创建销毁的系统消耗,提高性能。 提高响应速度(不用创建销毁) 提...
  • Java 线程池.pptx

    2020-08-19 15:19:31
    讲述了java线程池的优点,参数,6种线程池的使用场景,线程池用到的handler,线程任务的提交方式等等。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,149
精华内容 459
关键字:

java线程池的使用场景

java 订阅