最近精读Netty源码,读到NioEventLoop部分的时候,发现对Java线程&线程池有些概念还有困惑, 所以深入总结一下

线程创建

Java线程创建主要有三种方式:继承Thread类、实现Runable接口、实现Callable接口

只有通过调用Thread.start() 方法才会真正创建一个线程, 调用Thread.run() 并不会

当调用线程关心任务执行结果时,我们应选择实现Callable接口的方式创建线程

  • 继承方式实现创建线程

    @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接口的方式创建线程,这种方式调用线程无法感知任务线程执行结果(是否执行、成功或者异常)

    @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线程是使用系统内核线程实现, 所以先来简单回顾下系统内核线程的状态

内核线程的状态

  • Ready状态:当前线程已经就绪,等待系统调度
  • Running状态:当Ready状态的线程分配到时间片后进入该状态
  • Blocking状态:运行中的线程因为其他资源未就绪进入该状态

Java线程的状态

  • NEW: 实例化一个Thread对象后未调用start方法前都是该状态
  • RUNNABLE: JVM里面的可执行状态,对应内核线程的Ready或者Running状态。所以该状态下线程不一定在在运行,有可能在等待调度
  • WAITING: 等待状态,需要其他线程唤醒后才能重新进入RUNNABLE状态
  • TIMED_WAITING:超时等待,等待一定的时间或者被其他线程唤醒之后可再进入RUNNABLE状态
  • BLOCKED:阻塞状态,特指等待进入synchronized同步块的状态(获取监视器锁)
  • Termination:终态

只有待获取监视器锁时才是阻塞状态,获取Java语言实现的锁(ReentrantLock等)是等待状态。二者的区别在于监视器锁的实现依赖内核变量。

异常处理

假设一段业务逻辑没有考虑运行时异常, 而运行时异常又刚好发生了,那么对应的线程就会直接崩溃。所以多线程环境下为了让程序更加健壮稳定, 我们需要捕获异常。

  • 将整个业务逻辑加上异常捕获(当然代码就不是很优雅)

    @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线程收到这个信号,可以处理也可以不处理。

  • 中断相关的API
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状态

Java线程池一:线程基础的更多相关文章

  1. java 线程池(线程的复用)

    一. 线程池简介 1. 线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池.使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动 ...

  2. 由浅入深理解Java线程池及线程池的如何使用

    前言 多线程的异步执行方式,虽然能够最大限度发挥多核计算机的计算能力,但是如果不加控制,反而会对系统造成负担.线程本身也要占用内存空间,大量的线程会占用内存资源并且可能会导致Out of Memory ...

  3. -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中

     本文关键词: java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁  sleep()和wait()方法的区别 为什么wait( ...

  4. Java多线程、线程池和线程安全整理

    多线程 1.1      多线程介绍 进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 1.2      Thread类 通 ...

  5. Java多线程系列 JUC线程池03 线程池原理解析(二)

    转载  http://www.cnblogs.com/skywang12345/p/3509954.html  http://www.cnblogs.com/skywang12345/p/351294 ...

  6. Java多线程系列 JUC线程池02 线程池原理解析(一)

    转载  http://www.cnblogs.com/skywang12345/p/3509960.html ; http://www.cnblogs.com/skywang12345/p/35099 ...

  7. Java多线程系列 JUC线程池01 线程池框架

    转载  http://www.cnblogs.com/skywang12345/p/3509903.html 为什么引入Executor线程池框架 new Thread()的缺点 1. 每次new T ...

  8. Java多线程系列 JUC线程池07 线程池原理解析(六)

     关闭“线程池” shutdown()的源码如下: public void shutdown() { final ReentrantLock mainLock = this.mainLock; // ...

  9. 基于线程池的线程管理(BlockingQueue生产者消费者方式)实例

    1.线程池管理类: public class ThreadPoolManager { private static ThreadPoolManager instance = new ThreadPoo ...

  10. ReentrantLock+线程池+同步+线程锁

    1.并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行. 2)可见性 可见性指多个线程操作一个共享变量时,其中一个线程对变量 ...

随机推荐

  1. 考场(NOIP/ICPC)沙雕错误锦集(大赛前必看,救命提分良药)

    记住,无论什么测试,一定要先打三题暴力(至少不会被屠得太惨) 2018.10.4 1.记得算内存.(OI一年一场空,没算内存见祖宗) 2018.10.6 1.在二分许多个字符串时(二分长度),要以长度 ...

  2. PASS模型-第一周个人报告

    PASS模型-第一周个人报告 博客班级 https://edu.cnblogs.com/campus/zjcsxy/SE2020 作业要求 https://edu.cnblogs.com/campus ...

  3. 【Java】类的结构

    类与对象 类中主要包括五种结构,下面进行对这五种结构进行详细的介绍. 1. 面向对象与面向过程 面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做. 面向对象:强调具备了功能的对象,以类/对象为 ...

  4. Codeforces 1404 D. Game of Pairs

    Codeforces 1404 D.Game of Pairs 给定\(2n\)个数\(1,2,...,2n\),A 和 B 将进行交互,规则如下: A 需要将元素分成 n 组 \(\mathbf{p ...

  5. fflush(stdin)和fflush(stdout)

    转自:http://blog.csdn.net/yeyuangen/article/details/6743416 fflush(stdin)即清理标准输入流,把多余的仍未被保存的数据丢掉. fflu ...

  6. C++动态存储方式与静态存储方式

    如果从变量值存在的时间(即生存期)来分,可将程序中的变量分为:动态存储方式和静态存储方式.它们所占用的存储空间区域不同. C++存储空间区域 代码区:存放可执行程序的程序代码.静态存储区:存放静态变量 ...

  7. JS小案例:循环间隔重复变色

    在A.B.C三个区块中,有且仅有一个红色,要求红色每隔一秒即进入下一个区块,变色过程不断循环往复. 参考代码: <!DOCTYPE html> <html lang="zh ...

  8. react 中组件状态的一些理解

    组件状态:即 state 只有当state发生变化时,组件才会更新. 当一个html标签的值依赖于state的值得时候,如果state的值没有更新时,这个标签的值无论如何也是不会更新的. 看下面示例: ...

  9. go语言协程安全map

    前言: 在go语言中 map 是很重要的数据结构.Map 是一种无序的键值对的集合.Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值.问题来了,这么安逸的 数据结构 ...

  10. netty简介2

    作者:知乎用户 链接:https://www.zhihu.com/question/24322387/answer/282001188 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业 ...