我们在之前的线程学习中,都是之间创建新的线程,显性线程,用的时候开启,用完销毁,效率低且不安全 而且我们看到在阿里巴巴代码规范规约中也是不建议显式创建线程,建议使用线程池。
不管是继承Thread还是遵从Runnable接口,都需要重写Run方法,而且每一个线程对象有且只能执行一次,之后就会被销毁。 利用Runnable接口来提供执行目标,而且借助于Thread执行线程。
用生活中的例子来理解:
一个餐厅 服务人员 餐厅会按照餐桌比例安排服务员人数。 每一个服务员我们都可以看做是一个线程对象 需要告知服务器做什么事情就可以了,相对于告知线程对象执行目标是什么 当你来餐厅之前,服务员在这里,你走之后,服务员依然在这类。
线程池 ==> 可以容纳多个线程的容器
程序可以从线程池获取线程来完成目标代码 同时也可以将线程归还给线程池。 省去了创建线程和销毁线程这样非常繁琐的操作。节省时间。
线程池使用
public static ExecutorService newFixedThreadPool(int nThreads); 得到一个线程池对象,初始化参数是要求的当前线程池中的线程数
在这行代码中, newFixedThreadPool是ExecutorService类中的方法 返回值是ExecutorService,参数是int类型的线程数量。 创建代码示例为:
ExecutorService service = Executors.newFixedThreadPool(5);
public Future submit(Runnable target);
从线程池中获取一个线程对象,并且执行给定的Runnable接口实现类对象作为执行目标
代码如下:
package executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Thread1 implements Runnable{
@Override
public void run() {
System.out.println("启动成功");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("执行代码成功");
}
}
public class Demo1 {
public static void main(String[] args) {
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
Thread1 thread1 = new Thread1();
newFixedThreadPool.submit(thread1);
newFixedThreadPool.submit(thread1);
newFixedThreadPool.submit(thread1);
newFixedThreadPool.submit(thread1);
newFixedThreadPool.submit(thread1);
// 因为原本的5个线程都在被使用中,这里需要等待5个线程执行完毕,出现空闲线程
// 来执行对应的目标代码
newFixedThreadPool.submit(thread1);
newFixedThreadPool.submit(thread1);
newFixedThreadPool.submit(new Thread1());
newFixedThreadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类");
}
});
// 4. 关闭线程池
// 一般不用关闭线程池,会随着程序的退出而关闭
newFixedThreadPool.shutdown();
}
}
ps:匿名内部类的使用虽说很香,但是还不够香,下边我们就要从匿名内部类引出Lambda表达式。