一、线程池
现有问题:
线程是宝贵的内存资源,单个线程约占1MB的空间,过多分配易造成内存溢出
频繁的创建及销毁线程会增加虚拟机回收频率、资源开销,造成程序性能下降
定义:线程容器,可设定线程分配的数量上限
将预先创建的线程对象存入池中,并重用线程池中的线程对象。
避免频繁的创建和销毁
线程池原理:将任务提交给线程池,由线程池分配线程、运行任务,并在当前任务结束后复用线程。
二、获取线程池
常用线程池接口和类(所在包:java.util.concurrent)
Executor:线程池的*接口
ExecutorService:线程池接口,可通过submit(Runnable task)提交任务代码
Executors工厂类:通过此类可以获得一个线程池。
package com.monv.chatper14_1; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Executor : 线程池的根接口,execute() * ExecutorService : 包含管理线程池的一些方法,submit shutdown * ThreadPoolExecutor * SheduledThreadPoolExecutor * Executors:创建线程池的工具类 * (1)创建固定线程个数的线程池 * (2)创建缓存线程池,由任务的多少决定 * (3)创建单个线程池 * (4)创建调度线程池 调度:周期、定时执行 * @author Monv * */ public class Demo1 { public static void main(String[] args) { //1.1创建固定线程的线程池 //ExecutorService es = Executors.newFixedThreadPool(4); //1.2创建缓存线程池 ExecutorService es = Executors.newCachedThreadPool(); //1.3创建单个线程池 //Executors.newSingleThreadExecutor(); //1.4创建调度线程池 //Executors.newScheduledThreadPool(2); //2.创建线程 (卖票的案例) Runnable ru = new Runnable() { private int ticket = 100; @Override public void run() { // TODO Auto-generated method stub while(true) { if(ticket <=0) { break; } System.out.println(Thread.currentThread().getName()+"卖了"+ticket+"张票"); ticket--; } } }; //3.提交线程 for(int i =0;i<5;i++) { es.submit(ru); } //4.关闭线程池 es.shutdown();//如果任务正在执行,等所有任务执行完毕,再关闭线程池 // es.shutdownNow();//不会等待,立即关闭 } }
三、Callable接口创建线程
public interface Callable<V>{
public V call() throws Exception;
}
Callable接口是JDK1.5加入的,与Runnable接口类似,实现之后代表一个线程任务。
Callable具有泛型返回值、可以声明异常
Callable和Runnable接口的区别
1.Callable接口中的Call方法有返回值,Runnable接口中的Run方法没有返回值
2.Callable接口中的Call方法有声明异常,Runnable接口中的Run方法没有异常
注:Callable不能直接交给线程 需要把Callable转换为可执行的任务 用FutureTask接口来转换 这个接口继承了Runnable接口
1.用Callable执行0-100 的和
package com.monv.chatper14_1; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; /** * 演示Callable的使用 * Callable 和 Runnable接口的区别 * (1)Callable 接口中的Call方法有返回值,Runnable接口中的Run方法没有返回值 * (2)Callable 接口中的Call方法有声明异常,Runnable接口中的Run方法没有异常 * @author Monv * */ public class Demo2 { public static void main(String[] args) throws Exception{ //功能需求:使用Callable计算1-100的和 //1.创建Callable对象 Callable<Integer> callable = new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName()+"开始计算"); int sum = 0; for (int i =1;i<=100;i++) { sum+=i; } return sum; } }; //2.Callable不能直接交给线程 要把Callable对象转换为可执行的任务 FutureTask<Integer> task= new FutureTask<>(callable); //3.创建线程 Thread thread = new Thread(task); //4.启动线程 thread.start(); //5.获取结果 Integer sum = task.get(); System.out.println("结果是:"+sum); } }
2.使用线程池实现1-100的和
package com.monv.chatper14_1; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 用线程池实现1-100的和 * @author Monv * */ public class Demo3 { public static void main(String[] args) throws Exception { //1.创建线程池 ExecutorService es = Executors.newFixedThreadPool(1); //2.提交任务 Future:表示将要执行完任务的结果 Future<Integer> future = es.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println(Thread.currentThread().getName()+"开始计算"); int sum = 0 ; for (int i =1;i<=100;i++) { sum+=i; } return sum; } }); //3.获取任务的结果 System.out.println("结果为:"+future.get()); //4.关闭线程池 es.shutdown(); } }
3.用Future 两个任务并发执行0-50 51-100 的和
package com.monv.chatper14_1; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 用Future 两个任务并发执行0-50 51-100 的和 * @author Monv * */ public class Demo4 { public static void main(String[] args) throws Exception{ //1.创建线程池 ExecutorService es= Executors.newFixedThreadPool(2); //2.提交任务 Future<Integer> future1 = es.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { int sum = 0; for(int i =1;i<=50;i++) { sum+=i; } System.out.println("1-50计算完毕!"); return sum; } }); Future<Integer> future2 = es.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { int sum = 0; for(int i =51;i<=100;i++) { sum+=i; } System.out.println("51-100计算完毕!"); return sum; } }); //3.得到结果 int sum = future1.get()+future2.get(); System.out.println("1-100结果为:"+sum); //4.关闭线程池 es.shutdown(); } }
4.Future接口
Future:表示将要完成任务的结果,可以通过Future来获得结果
表示ExecutorService.submit()所返回的状态结果,就是call()返回值。
方法:V get()以阻塞形式等待Future中的异步处理结果(call()的返回值)
5.线程的同步及异步
同步:形容一次方法调用,同步一旦开始,调用者必须等待该方法返回,才能继续 只要有等待 就是同步。一条执行路径
异步:形容一次方法调用,异步一旦开始,像是一次消息传递,调用者告知之后立刻返回。二者竞争时间片,并发执行。多条执行路径