Java线程池一:线程基础
最近精读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线程池一:线程基础的更多相关文章
- java 线程池(线程的复用)
一. 线程池简介 1. 线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池.使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动 ...
- 由浅入深理解Java线程池及线程池的如何使用
前言 多线程的异步执行方式,虽然能够最大限度发挥多核计算机的计算能力,但是如果不加控制,反而会对系统造成负担.线程本身也要占用内存空间,大量的线程会占用内存资源并且可能会导致Out of Memory ...
- -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中
本文关键词: java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait( ...
- Java多线程、线程池和线程安全整理
多线程 1.1 多线程介绍 进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 1.2 Thread类 通 ...
- Java多线程系列 JUC线程池03 线程池原理解析(二)
转载 http://www.cnblogs.com/skywang12345/p/3509954.html http://www.cnblogs.com/skywang12345/p/351294 ...
- Java多线程系列 JUC线程池02 线程池原理解析(一)
转载 http://www.cnblogs.com/skywang12345/p/3509960.html ; http://www.cnblogs.com/skywang12345/p/35099 ...
- Java多线程系列 JUC线程池01 线程池框架
转载 http://www.cnblogs.com/skywang12345/p/3509903.html 为什么引入Executor线程池框架 new Thread()的缺点 1. 每次new T ...
- Java多线程系列 JUC线程池07 线程池原理解析(六)
关闭“线程池” shutdown()的源码如下: public void shutdown() { final ReentrantLock mainLock = this.mainLock; // ...
- 基于线程池的线程管理(BlockingQueue生产者消费者方式)实例
1.线程池管理类: public class ThreadPoolManager { private static ThreadPoolManager instance = new ThreadPoo ...
- ReentrantLock+线程池+同步+线程锁
1.并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行. 2)可见性 可见性指多个线程操作一个共享变量时,其中一个线程对变量 ...
随机推荐
- Centos8防火墙设置
1.centos中firewalld与iptables centos7以前的版本默认使用iptables服务进行管理防火墙规则.centos7以及其以上版本默认使用firewalld服务管理防火墙.所 ...
- .netcore使用autofac
.netcore3.1使用autofac (.netcore中本身已经实现了IOC容器,其实没有必要替换成autofac.如果非常习惯autofac,替换也是无可厚非的.) 第一步.在项目中引入Aut ...
- 作为servlet容器的hi-nginx-java
hi-nginx-java是一个独立于java官方的servlet规范,它有能力把NGINX直接编成servlet容器服务器.换言之,无需安装tomcat等容器服务器,也无需使用nginx的反向代理功 ...
- C++在C的基础上改进了哪些细节
C++ 是在C语言的基础上改进的,C语言的很多语法在 C++ 中依然广泛使用,例如: C++ 仍然使用 char.short.int.long.float.double 等基本数据类型: ...
- mysql优化之2--索引优化
1. 创建联合索引时,要注意,离散度大的列前置. 可以通过 select count(distinct(A)),count(distinct(B)) from tb; 看哪个列离散度大. 2. 索引列 ...
- Servlet与通信协议概述
Servlet 是一个java应用程序,一个Servlet应用有一个或多个Servlet程序,JSP页面会被转换和编译成Servlet程序. Servlet应用无法独立运行,必须运行在Servlet容 ...
- tcp 客户端 发送syn
简介 sys_connect->inet_stream_connect->inet_stream_connect->tcp_v4_connect->tcp_connect对于t ...
- Socket shutdown close简要分析
shutdown 系统调用关闭连接的读数据通道 写数据通道 或者 读写数据通道: 关闭读通道:丢弃socket fd 读数据以及调用shutdown 后到达的数据: 关闭写通道:不同协议处理不同:t ...
- leetcode bitmap系列问题整理
1. 题目: 编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 '1' 的个数(也被称为汉明重量). 示例 : 输入: 11输出: 3解释: 整数 11 的二进制表示为 000000 ...
- 利用火焰图分析ceph pg分布
前言 性能优化大神Brendan Gregg发明了火焰图来定位性能问题,通过图表就可以发现问题出在哪里,通过svg矢量图来查看性能卡在哪个点,哪个操作占用的资源最多 在查看了原始数据后,这个分析的原理 ...