最近精读Netty源码,读到NioEventLoop部分的时候,发现对Java线程&线程池有些概念还有困惑, 因此深刻总结一下
Java线程池一:线程基础
Java线程池二:线程池原理html
Java线程建立主要有三种方式:继承Thread类、实现Runable接口、实现Callable接口java
只有经过调用Thread.start()
方法才会真正建立一个线程, 调用Thread.run()
并不会多线程
当调用线程关心任务执行结果时,咱们应选择实现Callable接口的方式建立线程异步
继承方式实现建立线程ide
@Test public void testCreate_1() { Thread t = new Thread() { @Override public void run() { System.out.println(Thread.currentThread().getName()); throw new RuntimeException(); } }; t.start(); t.run(); }
实现Runnable接口的方式建立线程,这种方式调用线程没法感知任务线程执行结果(是否执行、成功或者异常)oop
@Test public void testCreate_2() { Thread t = new Thread(() -> System.out.println(Thread.currentThread().getName())); t.start(); }
实现Callable接口,调用线程经过FutureTask对象获取执行结果(返回值或者异常)线程
@Test public void testCreate_3() throws ExecutionException, InterruptedException { FutureTask<Integer> task = new FutureTask<>(() -> { throw new RuntimeException(); }); new Thread(task).start(); System.out.println(task.get()); }
咱们知道Java线程是使用系统内核线程实现, 因此先来简单回顾下系统内核线程的状态code
只有待获取监视器锁时才是阻塞状态,获取Java语言实现的锁(ReentrantLock等)是等待状态。两者的区别在于监视器锁的实现依赖内核变量。htm
假设一段业务逻辑没有考虑运行时异常, 而运行时异常又恰好发生了,那么对应的线程就会直接崩溃。因此多线程环境下为了让程序更加健壮稳定, 咱们须要捕获异常。对象
将整个业务逻辑加上异常捕获(固然代码就不是很优雅)
@Test public void testExceptionHandle_1() { new Thread(() -> { try { //business code int a = 1, b = 0; a = a / b; } catch (Throwable th) { //log } }).start(); }
使用FutureTask异步回掉处理异常(更加优雅,业务逻辑和异常处理逻辑分离)
@Test public void testExceptionHandle_2() { //业务逻辑 FutureTask<Integer> ft = new FutureTask<>(() -> { //business code int a = 1, b = 0; a = a / b; return a; }); Thread t = new Thread(() -> { ft.run(); handleResult(ft); }); t.start(); } //异常处理逻辑 private void handleResult(FutureTask<Integer> ft) { try { System.out.println("the result is " + ft.get()); } catch (InterruptedException e) { //log or ... e.printStackTrace(); } catch (ExecutionException e) { //log or ... e.printStackTrace(); } }
Java中断是一种线程间通讯手段。好比A线程给B线程发送一个中断信号,B线程收到这个信号,能够处理也能够不处理。
void thread.interrupt();//实例方法-中断线程(线程的中断标识位置为1) boolean thread.isInterrupted();//线程是否中断 & 不清除中断标识 static boolean Thread.interrupted();//当前线程是否中断 & 清除中断标识
实例
线程t_1每次循环会判断当前线程的中断状态,若是当前线程已经被中断(中断标识位为1)就直接返回;
整个通讯过程:主线程把t_1线程的中断标识位置为1,t_1获取到中断标识位为1, 而后结束循环。
@Test public void testInterrupt() throws InterruptedException { Thread t_1 = new Thread(() -> { int i = 0; while (true) { boolean isInterrupt = Thread.interrupted(); if (isInterrupt) { System.out.println("i am interrupt, return"); return; } //business code if (i++ % 10000 == 0) { System.out.println(i); } } }); t_1.start(); for (int i = 0; i < 100000; i++) { ; } t_1.interrupt(); }
守护线程
当JVM中的全部的用户线程都退出后守护线程也会退出
优先级
线程的优先级越高,越有可能更快的执行或者得到更多的可执行时间单元。可是Java线程的优先级只是参考,依赖于具体的实现
thread.join()
调用线程进入WAITING状态,直到thread线程终止
thread.yield()
当前线程让出cpu资源,仍处于RUNNABLE状态