new Thread() 方式

执行一个异步任务,我们可以这样做

new Thread(new Runnable() {

    @Override
    public void run() {
        System.out.println("ThreadName:"+Thread.currentThread().getName());
    }
}).start();

以上方式是可以实现的,但是存在诸多弊端:

  1. 每次都重新 new Thread 新建对象耗费性能;

  2. 缺乏统一管理,并发情况下可能无休止的创建线程,随时可能 oom;

  3. 无法灵活执行线程,如定时、公平、中断等;

  4. 针对耗时较短的异步行为,浪费资源及时间(如下图)
    Thread生命周期
    以上我们可以看到,真正的运行状态其实只占整个 Thread 生命周期的一小部分,如果只是为了执行一个耗时或占用资源较小的操作,可能开启线程的消耗比线程工作的周期还要长。
    相比 new Thread,Java 提供了四种线程池可用

    • Executors.newCachedThreadPool(); // 可伸缩线程池
    • Executors.newFixedThreadPool(5); // 固定数量线程池
    • Executors.newSingleThreadExecutor(); // 单一线程池
    • Executors.newScheduledThreadPool(5); // 可定时执行线程池
      其实还有一种 single 和 schedule 的结合体
    • Executors.newSingleThreadScheduledExecutor();
  5. newCachedThreadPool
    创建一个可伸缩的缓存线程,如果线程池长度超过需要处理的长度,则收回部分线程,如果没有可收回的,就创建新线程,代码如下

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

    结果如下, 当需要执行第 7 个的时候,重复使用了线程 1

    pool-1-thread-1
    pool-1-thread-2
    pool-1-thread-3
    pool-1-thread-4
    pool-1-thread-5
    pool-1-thread-6
    pool-1-thread-1
    pool-1-thread-7
    pool-1-thread-8
    pool-1-thread-9
  6. newFixedThreadPool
    创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。示例代码如下:

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

    因为线程池大小为 4 个,每个任务输出后等待 2 秒,所以每次会打印 4 个线程名字。
    定长线程池大小最好是根据业务需求和机器资源配置进行设置,选择一个合适的数字,而不是随意想写多少就写多少。

  7. newScheduledThreadPool

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

     ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
     scheduledThreadPool.schedule(new Runnable() {
    
         @Override
         public void run() {
             System.out.println("delay 3 seconds");
         }
     }, 3, TimeUnit.SECONDS);
首次延期1S,然后每3S执行一次,倒计时3次之后,则退出定时器
```
CountDownLatch countDownLatch = new CountDownLatch(3);
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {

    @Override
    public void run() {
        System.out.println("delay 3 seconds");
        countDownLatch.countDown();
    }
}, 1,3, TimeUnit.SECONDS);
try {
    System.out.println("开始等待倒计时...");
    countDownLatch.await();
} catch (InterruptedException e) {
    e.printStackTrace();
}
System.out.println("倒计时结束");
if (countDownLatch.getCount() == 0L) {
    scheduledThreadPool.shutdown();
}
```
  1. newSingleThreadExecutor
    创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务

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

    会按照顺序依次执行。

  • 线程
    77 引用 • 80 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    2344 引用 • 6790 回帖 • 1180 关注
感谢    关注    收藏    赞同    反对    举报    分享