一个线程执行任务的完整流程是:
这个流程中创建线程和关闭线程耗费的时间在90%,而我们有时候创建线程就是为了执行一个很小的任务,这就会导致效率很低。
而线程池就是一个容纳多个线程的容器,池中的线程可以反复的使用,省去了频繁创建和销毁线程的时间。
线程池分为定长和非定常线程池,线程池的结构可以看作是数组形式,每个下标放一个线程。
Java中有四种线程池:
对获取以上四种线程池的对象,用的都是:ExecutorService 对象名 = Executors.newCachedThreadPool( ) ;
缓存线程池 (长度无限制)
执行流程:
ExecutorService service = Executors.newCachedThreadPool();
//向线程池中 加入 新的任务
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName());
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName());
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName());
}
});
举例:
public class demo7 {
public static void main(String[] args) {
//创建线程池对象
ExecutorService service = Executors.newCachedThreadPool();
//往线程池里面放入新的任务
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"窗前明月光");
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"窗前明月光");
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
service.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"窗前明月光");
}
});
}
}
打印结果:
pool-1-thread-2窗前明月光
pool-1-thread-1窗前明月光
pool-1-thread-2窗前明月光
解释:
往线程池放入两个任务,暂停一秒后再放入第三个任务,可以看到任务一和任务三的线程名称一样。
定长线程池(长度是指定的数值)
执行流程:
ExecutorService service = Executors.newFixedThreadPool(2); //在这里确定线程池的长度
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName());
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName());
}
});
效果与定长线程池创建时传入数值1效果一致
执行流程:
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName());
}
});
service.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程的名称:"+Thread.currentThread().getName());
}
});
周期任务定长线程池执行流程:
判断线程池是否存在空闲线程
存在则使用
不存在空闲线程,且线程池未满的情况下,则创建线程并放入线程池, 然后使用
不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
周期性定长线程池是一个定长线程池,可以使任务定时在某个时间执行,也可以使任务定期并周期执行。
举例:
public class demo7_2 {
/**
* 周期性任务定长线程池
*/
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
//1.定时执行一次
/**
* 参数1. 定时执行的任务
* 参数2. 时长数字
* 参数3. 时长数字的时间单位。TimeUnit的常量指定
*/
service.schedule(new Runnable() {
@Override
public void run() {
System.out.println("床前明月光");
}
},5, TimeUnit.SECONDS); //5,单位:秒
//周期执行任务
/**
* 参数1. 任务
* 参数2, 延时时长数字(第一次执行在什么时候以后)
* 参数3, 周期时长数字(每隔多久执行一次)
* 参数4, 时长数字单位
*/
service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("床前明月光");
}
},5,1,TimeUnit.SECONDS); //5秒后第一次执行,后每隔1秒执行一次
}
}
Lambda表达式是函数式编程思想,意思是写一个方法(函数)直接解决问题,而不像面向对象一样创建对象调用方法来解决问题。
举例:
public static void main(String[] args) {
//冗余Runnable代码
Thread t= new Thread(new Runnable() {
@Override
public void run() {
System.out.println("床前明月光");
}
});
t.start();
//函数式编程
Thread t1 = new Thread(() -> System.out.println("床前明月光"));
t1.start();
}
public static void main(String[] args) {
//冗余Runnable代码
Thread t= new Thread(new Runnable() {
@Override
public void run() {
System.out.println("床前明月光");
}
});
t.start();
//函数式编程
Thread t1 = new Thread(() -> System.out.println("床前明月光"));
t1.start();
}