在使用多线程技术时,通常会创建和销毁大量的线程,占用了很多的系统资源,这对系统的性能造成了很大的影响。
在 JDK 5之后引进了 Executor 框架,也就是线程池技术,通过 Executor 来启动线程比使用 Thread 的 start 方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免 this 逃逸问题。
线程池中可以设置线程的初始数量,以及一些线程的操作方法。
ExecutorService 表示一个线程池实例.
Executors 是一个工厂类, 能够创建出几种不同风格的线程池.
ExecutorService 的 submit 方法能够向线程池中提交若干个线程任务.
ExecutorService 的 shutdown() 方法可以关闭线程池.
Demo 代码示例:
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() );
}
}
class ExecutorsDemo {
public static void main(String[] args) {
// 创建一个线程池对象,控制要创建几个线程对象。
ExecutorService pool = Executors.newFixedThreadPool(4);
// 可以执行Runnable对象或者Callable对象代表的线程
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
//结束线程池
pool.shutdown();
}
}
运行结果:通过结果可以看出线程池最大线程数量是 4 ,所以就只创建了四个线程,当执行第五个任务时不继续创建线程而是去线程池中去调用之前创建的线程。
Demo 代码示例:
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() );
}
}
class ExecutorsDemo {
public static void main(String[] args) {
// 创建一个有缓存功能的线程池对象,并动态创建线程对象。
ExecutorService pool = Executors.newCachedThreadPool();
// 可以执行Runnable对象或者Callable对象代表的线程
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
//结束线程池
pool.shutdown();
}
}
运行结果:通过结果可以看出有多少个线程任务就创建了多少线程对象。但是也不能一概而论,因为线程池只要不关闭,其中的线程就一直存在,所以有时候也可能是继续调用线程池中已经存在的线程。
Demo 代码示例:
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() );
}
}
class ExecutorsDemo {
public static void main(String[] args) {
// 创建一个只有单线程的线程池
ExecutorService pool = Executors.newSingleThreadExecutor();
// 可以执行Runnable对象或者Callable对象代表的线程
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
pool.submit(new MyRunnable());
//结束线程池
pool.shutdown();
}
}
运行结果:通过结果可以看出,线程池中只创建了一个线程对象,五次线程任务调用了同一个线程对象。
在开发中经常需要一些周期性的操作,例如每隔几分钟就进行某一项操作。这时候我们就要去设置个定时器,Java中最方便、最高效的实现方式是用java.util.Timer工具类,再通过调度java.util.TimerTask任务。
Timer是一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。实际上是个线程,定时调度所拥有的TimerTasks。
TimerTask是一个抽象类,它的子类由 Timer 安排为一次执行或重复执行的任务。实际上就是一个拥有run方法的类,需要定时执行的代码放到run方法体内。
Timer:定时器
TimerTask:定时任务
继承 TimerTask 抽象类实现定时任务
public class TimerDemo {
public static void main(String[] args) {
// 创建定时器对象
Timer t = new Timer();
// 3秒后执行定时任务,并结束任务
t.schedule(new MyTask(t), 3000);
}
}
// 继承 TimerTask 类,将此类定义为定时任务类
class MyTask extends TimerTask {
private Timer t;
public MyTask(){}
public MyTask(Timer t){
this.t = t;
}
@Override
public void run() {
System.out.println("该学习了孩子");
t.cancel();//取消任务
}
}
public class TimerDemo2 {
public static void main(String[] args) {
// 创建定时器对象
Timer t = new Timer();
// 3秒后执行定时任务第一次,如果不成功,每隔2秒再继续炸
t.schedule(new MyTask2(), 3000, 2000);
}
}
// 继承 TimerTask 类,将此类定义为定时任务类
class MyTask2 extends TimerTask {
@Override
public void run() {
System.out.println("孩子,该学习了");
}
}
public class TimerDemo {
public static void main(String[] args) throws InterruptedException {
// 创建定时器
Timer timer = new Timer("myTimer");
// 创建定时任务
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println(LocalDateTime.now() + "孩子~该学习了");
}
};
Date nextMinute = nextMinute();
System.out.println("now:" + new Date() + ", execute:" + nextMinute);
// 添加任务定义时间
timer.schedule(timerTask ,nextMinute);
}
// 获取下一分钟的时间
private static Date nextMinute(){
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 1);
calendar.add(Calendar.SECOND, -calendar.get(Calendar.SECOND));
return calendar.getTime();
}
}