本篇博客主要讲解四大线程池的用法和各自的特点,所以对于线程池的构造或者参数不是很了解的可以去看看这篇博客http://blog.csdn.net/lift_class/article/details/70216690
相关参考博客地址:http://blog.csdn.net/qq497930909/article/details/72876278
本篇博客Demo地址:http://download.csdn.net/detail/g_ying_jie/9901935
/*
* 可缓存线程池:CachedThreadPool
* 1. 这种线程池内部没有核心线程,线程的数量是有没限制的。
* 2. 在创建任务时,若有空闲的线程时则复用空闲的线程,若没有则新建线程。
* 3. 没有工作的线程(闲置状态)在超过了60S还不做事,就会销毁。
* */
ExecutorService mCachedThreadPool = Executors.newCachedThreadPool();
这里用线程休眠模拟下载,并实时反馈下载进度条
//开始下载
private void startDownload(final ProgressBar progressBar, final int i) {
mCachedThreadPool.execute(new Runnable() {
@Override
public void run() {
int p = 0;
progressBar.setMax(10);//每个下载任务10秒
while (p < 10) {
p++;
progressBar.setProgress(p);
Bundle bundle = new Bundle();
Message message = new Message();
bundle.putInt("p", p);
//把当前线程的名字用handler让textview显示出来
bundle.putString("ThreadName", Thread.currentThread().getName());
message.what = i;
message.setData(bundle);
mHandler.sendMessage(message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
从上面两张图可看出:CachedThreadPool在有线程空闲时会直接复用执行任务,要注意的是CachedThreadPool设定的线程空闲时长的上限是60S,所以下载D时thread-1和thread-2已经被销毁,重新开启了thread-3来执行任务
/*
* 定长线程池:FixedThreadPool
* 1. 该线程池的最大线程数等于核心线程数,所以在默认情况下,该线程池的线程不会因为闲置状态超时而被销毁。
* 2. 如果当前创建线程数小于创建时设定的核心线程数并且有空闲的线程,FixedThreadPool也不会去复用之前的闲置线程,会创建新的线程去执行任务。
* 3. 如果当前创建线程数等于创建时设定的核心线程数,新来的任务将被将入到队列中等待执行
* */
ExecutorService mFixedThreadPool = Executors.newFixedThreadPool(3);//创建定长为3的线程池
还是原来的下载代码,只是将对象换成了FixedThreadPool
//开始下载
private void startDownload(final ProgressBar progressBar, final int i) {
mFixedThreadPool.execute(new Runnable() {
@Override
public void run() {
int p = 0;
progressBar.setMax(10);//每个下载任务10秒
while (p < 10) {
p++;
progressBar.setProgress(p);
Bundle bundle = new Bundle();
Message message = new Message();
bundle.putInt("p", p);
//把当前线程的名字用handler让textview显示出来
bundle.putString("ThreadName", Thread.currentThread().getName());
message.what = i;
message.setData(bundle);
mHandler.sendMessage(message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
上图可以看到:当前创建线程数2小于创建时设定的核心线程数3并且有空闲的thread-1,FixedThreadPool也不会去复用之前的闲置thread-1,会创建新的thread-3去执行任务。
上图可以看到:当前创建线程数等于创建时设定的核心线程数时,任务D和E会进入等待队列。
/*
* 单线程化的线程池:
* 1. 有且仅有一个工作线程执行任务
* 2. 所有任务按照指定顺序执行,即遵循队列的入队出队规则
* */
ExecutorService mSingleThreadPool = Executors.newSingleThreadExecutor();
上图可以看到:池中只有thread-1这一个线程,按顺序逐个执行任务。
好了开胃菜吃完了,下面是最精华的部分
/*
* ScheduledThreadPool 默认线程闲置上限10秒。这个线程池有点像是吧CachedThreadPool和FixedThreadPool 结合了一下。
* 1. 不仅设置了核心线程数,最大线程数也是Integer.MAX_VALUE。
* 2. 这个线程池是上述4个中为唯一个有延迟执行和周期执行任务的线程池。
* */
ScheduledExecutorService mScheduledThreadPool = Executors.newScheduledThreadPool(3);
下面这种用法前面已经演示很多了,就不在演示了,这个综合了一下CachedThreadPool和FixedThreadPool双方的特点,感兴趣的可以下载demo测试下
mScheduledThreadPool.execute(new Runnable() {
@Override
public void run() {
}
});
//延时下载
private void delayDown(final ProgressBar progressBar, final int i) {
mScheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
}
}, 3, TimeUnit.SECONDS);
}
TimeUnit枚举类型定义时间单位,3代表延时执行的时长,上述方法会延迟3秒后执行下载任务
/*
* 延时执行,并且间隔一段时间周期性执行
* 延迟0秒后执行任务,从开始执行任务这个时候开始计时,每7秒执行一次不管执行任务需要多长的时间。
* 当我们要执行的任务大于我们指定的执行间隔时,它并不会在指定间隔满足后开辟一个新的线程并发执行这个任务。而是等待该线程执行完毕。
* */
mScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
//....
}
},3, 7, TimeUnit.SECONDS);
//有时候我们希望一个任务被安排在凌晨3点(访问较少时)周期性的执行一个比较耗费资源的任务,可以使用下面方法设定每天在固定时间执行一次任务。
/**
* 每天晚上8点执行一次
* 每天定时安排任务进行执行
*/
private void delayCycleDown() {
long oneDay = 24 * 60 * 60 * 1000;
long initDelay = getTimeMillis("20:00:00") - System.currentTimeMillis();
initDelay = initDelay > 0 ? initDelay : oneDay + initDelay;
mScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
// TODO: 需要周期性执行的耗时线程体
}
}, initDelay, oneDay, TimeUnit.MILLISECONDS);
}
/**
* 获取指定时间对应的毫秒数
* @param time "HH:mm:ss"
* @return
*/
private static long getTimeMillis(String time) {
try {
DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
DateFormat dayFormat = new SimpleDateFormat("yy-MM-dd");
Date curDate = dateFormat.parse(dayFormat.format(new Date()) + " " + time);
return curDate.getTime();
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
/*
* 延时执行,并且间隔一段时间周期性执行
* 延迟3秒后执行任务,从任务完成时这个时候开始计时,7秒后再执行,再等完成后计时7秒再执行也就是说这里的循环执行任务的时间点是从上一个任务完成的时候。
* */
private void delayPeriodDown() {
mScheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
//....
}
}, 3, 7, TimeUnit.SECONDS);
}