高级多线程
线程池
问题:
- 线程是宝贵的内存资源,单个线程约占1MB空间,过多分配造成内存溢出
- 频繁的创建及销毁线程会增加虚拟机回收效率,资源开销,造成程序性能下降
线程池:
- 线程容器,可设定线程分配的数量上限
- 将预先创建的线程对象放入池中,并重用线程池中的线程对象
- 避免频繁的创建和销毁
线程池API
常用的线程池接口和类(所在包java.util.concurrent):
(1)Executor:线程的顶级接口,只有一个方法execute()
(2)ExecutorService:线程池接口,继承了Executor,包含了管理线程池的一些方法,如可以通过submit提交任务代码【重点关注ThreadPoolExecutor,ScheduledThreadPoolExecutor两个实现类】
(3)Executors工具类:通过此类可以获得一个线程池【1.创建固定线程个数线程池2.创建缓存线程池,数量由任务多少决定3.创建单线程池4.创建调度线程池,调度:周期、定时执行】
通过newFixedThreadPool(int nThreads) 获取固定数量的线程池。参数:指定线程池中线程的数量
通过newCachedThreadPool()获得动态数量的线程池,如不够则创建新的,没有上限
创建线程池
// 1.1创建4个线程的线程池(线程个数固定)
// ExecutorService es = Executors.newFixedThreadPool(4);
// 1.2创建缓存线程池,线程个数由任务个数决定
ExecutorService es = Executors.newCachedThreadPool();
// 1.3创建单线程 线程池
// ExecutorService es = Executors.newSingleThreadExecutor()
// 1.4创建调度线程池
// ExecutorService es = Executors.newScheduledThreadPool(corePoolSize);
// ExecutorService es = Executors.newSingleThreadExecutor()
Callable接口
package xiancheng_02;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
// Callable接口
public class CallableTest {
// 演示Callable接口的使用
// Callable和runnable的区别:
// 1. Callable接口中call方法返有返回值,Runnable接口中run方法没有返回值
// 2.Callable接口中call方法有声明异常,Runnable接口中run方法没有异常
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 {
// TODO Auto-generated method stub
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.获取结果(等待call方法执行完毕,才会返回)
Integer sum = task.get();
System.out.println("结果是"+sum);
}
}
Future接口
Future接口表示将要完成任务的结果,表示ExecutorService.submit()所返回的状态结果,就是call()的返回值。
V get() 以阻塞形式等待Future中的异步处理结果(call()的返回值)。
package xiancheng_02;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
// 使用两个线程,并发计算1-50,51-100的和,然后汇总
public class FutureJieKou {
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 {
// TODO Auto-generated method stub
// 计算1-50的和
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 {
// TODO Auto-generated method stub
// 计算51-100的和
int sum = 0;
for(int i=51;i<=100;i++) {
sum+=i;
}
System.out.println("51-100计算完毕........");
return sum;
}
});
// 3.获取结果(这里刚写完会报错,记得public static void main(String[] args) 这里抛出异常 throws Exception)
int sum = future1.get()+future2.get();
System.out.println("结果是"+sum);
// 4.关闭线程池
es.shutdown();
}
}
线程的同步
形容一次方法调用,同步一旦开始,调用者必须***等待***该方法返回,才能继续。(单条执行路径)
线程的异步
形容一次方法调用,异步一旦开始,像是一次消息传递,调用者告知之后立刻返回。二者竞争时间片,并发执行。(多条执行路径)
Lamda表达式
package xiancheng_03;
// 推导lambda表达式
public class Lambda {
// 3.静态内部类
static class Like2 implements ILike{
@Override
public void lambda() {
System.out.println("22222222222");
}
}
public static void main(String[] args) {
ILike like = new Like(); //接口去new一个实现类
like.lambda();
like =new Like2();
like.lambda();
//4.局部内部类
class Like3 implements ILike{
@Override
public void lambda() {
System.out.println("333333333333");
}
}
like = new Like3();
like.lambda();
//5.匿名内部类
like = new ILike() {
@Override
public void lambda() {
System.out.println("4444444444");
}
};
like.lambda();
//6.用lambda简化
like = ()-> {
System.out.println("55555555");
};
like.lambda();
}
}
// 1.定义一个函数式接口
interface ILike{
void lambda();
}
// 2.实现类
class Like implements ILike{
@Override
public void lambda() {
System.out.println("1111111111111");
}
}