一.线程休眠
休眠线程有两种实现:
a.使⽤ sleep 休眠
b.使⽤ TimeUnit 休眠
1.1 sleep 休眠
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
try {
Thread.sleep(60*1000);
} catch (InterruptedException e) {
System.out.println("我接收到了终止执行通知");
// e.printStackTrace();
}
});
thread.start();
Thread.sleep(1000);
System.out.println("终止子线程 thread");
thread.interrupt();
1.2TimeUnit 休眠
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
public class ThreadTimeUtil {
public static void main(String[] args) throws InterruptedException {
System.out.println("主线程开始执行了:"+ LocalDateTime.now());
TimeUnit.DAYS.sleep(1);//休眠一天
TimeUnit.HOURS.sleep(1);//⼩时
TimeUnit.MINUTES.sleep(1);//分
TimeUnit.SECONDS.sleep(1);//秒
TimeUnit.MILLISECONDS.sleep(1000);//毫秒
TimeUnit.MICROSECONDS.sleep(1000);//微妙
TimeUnit.NANOSECONDS.sleep(1000);//纳秒
}
}
二.线程状态
1.1打印所有线程状态
public static void main(String[] args) {
printState();//打印所有线程状态
}
private static void printState() {
for (Thread.State item : Thread.State.values()) {
System.out.println(item);
}
}
a.NEW: 新建状态,安排了工作还未开始行动。
b.RUNNABLE:运行状态,分为①RUNNABLE:得到时间片运行中的状态 ②Ready:未得到时 间片的就绪状态
c.BOLCKED:阻塞状态,当遇到锁时,会出现这种状态。
d.WAITING:无限期的等待状态 。
e.TIMED_WAITING:有明确结束时间的等待状态。
f.TERMINATED:终止状态,当线程任务结束之后会变成此状态。
1.2线程状态转变
public static void main(String[] args) throws InterruptedException {
// printState();//打印所有线程状态
Thread t1 = new Thread(() -> {
System.out.println("当前线程状态2:"+Thread.currentThread().getState());
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("当前线程状态:" + t1.getState());
t1.start();
//让主线程休眠1s
Thread.sleep(1000);
System.out.println("当前线程的状态3:" + t1.getState());
//等待子线程执行完
t1.join();
System.out.println("当前线程的状态4:" + t1.getState());
}
/**
* 打印所有线程状态
*/
private static void printState() {
for (Thread.State item : Thread.State.values()) {
System.out.println(item);
}
}
二.线程安全问题
2.1相关概念
概念:线程不安全指的是程序在多线程的执⾏结果不符合预期。
单线程:
static class Counter{
private int num=0;
private int MAX_COUNT=0;
public Counter(int MAX_COUNT){
this.MAX_COUNT=MAX_COUNT;
}
//++方法
public void increment(){
for (int i = 0; i < MAX_COUNT; i++) {
num++;
}
}
//--方法
public void decrement(){
int temp=0;
for (int i = 0; i < MAX_COUNT; i++) {
num--;
}
}
public int getNum(){
return num;
}
}
public static void main(String[] args) throws InterruptedException {
Counter counter=new Counter(100000);
counter.increment();
counter.decrement();
System.out.println("最终结果:"+counter.getNum());
}
多线程:
static class Counter{
private int num=0;
private int MAX_COUNT=0;
public Counter(int MAX_COUNT){
this.MAX_COUNT=MAX_COUNT;
}
//++方法
public void increment(){
for (int i = 0; i < MAX_COUNT; i++) {
num++;
}
}
//--方法
public void decrement(){
int temp=0;
for (int i = 0; i < MAX_COUNT; i++) {
num--;
}
}
public int getNum(){
return num;
}
}
public static void main(String[] args) throws InterruptedException {
Counter counter=new Counter(100000);
Thread thread1=new Thread(()->{
counter.increment();
});
Thread thread2=new Thread(()->{
counter.decrement();
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("最终结果:"+counter.getNum());
}
此时,多线程结果是不确定的。
2.2线程不安全原因
2.2.1抢占式执行
CPU资源有限,多个线程争抢着执行任务,就会导致线程不安全问题。
2.2.2 多个线程修改同⼀个变量
因为两个线程都是修改 num这个变量,线程在并发执行的时候会出现不安全的问题,但如果各自修改各自的变量,就不会出现这个问题。
static class Counter{
// private int num=0;
private int num1=0;
private int num2=0;
private int MAX_COUNT=0;
public Counter(int MAX_COUNT){
this.MAX_COUNT=MAX_COUNT;
}
//++方法
public int increment(){
for (int i = 0; i < MAX_COUNT; i++) {
num1++;
}
return num1;
}
//--方法
public int decrement(){
int temp=0;
for (int i = 0; i < MAX_COUNT; i++) {
num2--;
}
return num2;
}
public int getNum(){
return num1+num2;
}
}
public static void main(String[] args) throws InterruptedException {
Counter counter=new Counter(100000);
Thread thread1=new Thread(()->{
counter.increment();
});
Thread thread2=new Thread(()->{
counter.decrement();
});
thread1.start();
thread1.join();
thread2.start();
thread2.join();
System.out.println("最终结果:"+counter.getNum());
}
2.2.3非原子性操作
什么是原子性?
一段程序必须一次性执行完,中间不能停顿。
不保证原⼦性会给多线程带来什么问题?
如果⼀个线程正在对⼀个变量操作,中途其他线程插⼊进来了,如果这个操作被打断了,结果就可能是错误的。
2.2.4内存可见性
可⻅性指, ⼀个线程对共享变量值的修改,能够及时地被其他线程看到.
Java 内存模型 (JMM): Java虚拟机规范中定义了Java内存模型.
⽬的是屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到⼀致的并发效果.
a.
当线程要读取⼀个共享变量的时候, 会先把变量从主内存拷⻉到⼯作内存, 再从⼯作内存读取数据.
b.
当线程要修改⼀个共享变量的时候, 也会先修改⼯作内存中的副本, 再同步回主内存.
2.2.5指令重排序
编译器优化的本质是调整代码的执⾏顺序,在单线程下没问题,但在多线程下容易出现混乱,从⽽造成线程安全问题。