行僧

参与开源,努力提升。 我的GitHub地址:https://github.com/playingjoker

Java ExecutorService四种线程池的例子 有更新!

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();

  1. 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
  1. 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个线程名字。
定长线程池大小最好是根据业务需求和机器资源配置进行设置,选择一个合适的数字,而不是随意想写多少就写多少。

  1. 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();
    }
    
  2. 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();
    			}
    		}
    	});
    }
    

    会按照顺序依次执行。

评论

整理的都是基础:joy:

Wilder 回复

我居然都知道哈哈哈

liuzn 回复

:stuck_out_tongue_winking_eye: :stuck_out_tongue_winking_eye: :stuck_out_tongue_winking_eye:

validate
1,028 浏览