多线程
一、线程概念
进程是正在运行的程序,是系统资源调度的基本单位,一个进程至少有一个线程,线程中可以共享内存资源
例如:进程执行多件事情,例如一遍听音乐,一遍打游戏,线程是一个事可以分成多线程执行
二、线程创建方式
①继承Thread类
②实现Ruannable接口
③实现Callable接口,可以返回多线程结果
public class CallableImpl implements Callable<Object>{ @Override public Object call() throws Exception { // TODO Auto-generated method stub System.out.println("多线程:"+Thread.currentThread().getName()+"运行"); return Thread.currentThread().getName(); } } public static void main(String[] args) { int taskSize = 5;//设置任务数 //1.创建线程池 ExecutorService pool = new ThreadPoolExecutor(10,10,60,TimeUnit.SECONDS,new ArrayBlockingQueue<>(10)); //存储多线程返回值数据 List<Future> list = new ArrayList<Future>(); for (int i = 0; i < taskSize; i++) { // 2.创建callable实现类实例 CallableImpl thread = new CallableImpl(); // 3.线程池执行任务 future用来接受多线程返回结果 Future future = pool.submit(thread); list.add(future); } //4.关闭线程池 pool.shutdown(); //遍历多线程结果 for(Future f:list) { try { System.out.println(f.get()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
三、线程池
在阿里巴巴Java开发手册中提到,避免使用Executors创建线程池,主要是避免使用其中的默认实现,那么我们可以自己直接调用ThreadPoolExecutor的构造函数来自己创建线程池
正确创建方法:
ExecutorService executor = new ThreadPoolExecutor(corePoolSize,//核心线程数 maximumPoolSize, //最大线程数 keepAliveTime,//当线程空闲时,所允许保存的最大时间,超过这个时间,线程将被释放销毁,但只针对于非核心线程。 unit,//时间单位,TimeUnit.SECONDS等 workQueue,//任务队列 threadFactory,//创建线程的工厂类 handler//拒绝策略 );
任务委托给线程池几种方法:
execute(Runnable)//不返回值,如果任务不要求返回值,则选择execute,可以极大提高性能
submit(Runnable)//返回值
submit(Callable)//返回值
关闭线程池
shutdown()
仅停止阻塞队列中等待的线程,正在执行的线程会执行结束。
shutdownNow()
不仅会停止阻塞队列中的线程,而且会停止正在执行的线程。
线程池工作原理:
四、线程生命周期
五、线程安全问题
线程安全问题引起原因是多线程资源共享
解决办法:
1.使用同步机制,例如synchronized修饰方法或者变量
2.多线程之间不共享数据,或者共享的数据不做修改
六、线程间通信
可以通过管道进行线程间通信
七、Future和CompleteableFuture区别
创建异步操作,runAsync(不支持返回值) 和 supplyAsync方法(支持返回值)
计算结果完成时的回调方法
whenComplete:执行完当前任务的线程,继续执行 whenComplete 的任务。
whenCompleteAsync: 执行完当前任务的线程,把whenCompleteAsync 的任务继续提交给线程池来执行。
exceptionally:当前任务出现异常时,执行exceptionally中的回调方法。
thenApply :当一个线程依赖另一个线程时,可以使用 thenApply 方法来把这两个线程串行化。
handle :是执行任务完成时对结果的处理。
handle 方法和 thenApply 方法处理方式基本一样。不同的是 handle 是在任务完成后再执行,还可以处理异常的任务。thenApply 只可以执行正常的任务,任务出现异常则不执行 thenApply 方法。
thenAccept :消费处理结果,接收任务的处理结果,并消费处理,无返回结果。
thenRun 方法,跟 thenAccept 方法不一样的是,不关心任务的处理结果。只要上面的任务执行完成,就开始执行 thenAccept 。
thenCombine:合并任务,thenCombine 会把 两个 CompletionStage 的任务都执行完成后,把两个任务的结果一块交给 thenCombine 来处理。
thenCompose 方法:thenCompose 方法允许你对两个 CompletionStage 进行流水线操作,第一个操作完成时,将其结果作为参数传递给第二个操作