线程的状态和安全问题

1.线程状态

1.1 所有线程状态

for (Thread.State item : Thread.State.values()) {
           System.out.println(item);
}

在这里插入图片描述
线程状态(6种)
NEW(新建状态,当线程被新建,但是为启动(start方法)之前的状态)
RUNNABLE(运行状态【运行】{得到时间片运行中状态}【就绪】{未得到时间片就绪状态})
BLOCKED(阻塞状态【如果遇到锁,线程就会变为阻塞状态等待另一个线程释放锁】)
WAITING(等待状态,没有明确结束时间的等待)
TIMED_WAITING(有明确结束时间的等待)
TERMINATED(销毁状态,当线程结束完成之后就会变成此状态)

1.2 线程状态转变

在这里插入图片描述

2.线程安全问题

概念:线程不安全指的是程序在多线程的执行结果不符合预期。

2.1 线程安全问题导致的原因:

1.抢占式执行
2.多个线程同时修改了同一个变量
3.操作是非原子性操作
什么是原子性?
我们把一段代码想象成一个房间,每个线程就是要进入这个房间的人。如果没有任何机制保证,A进入房间之后,还没有出来;B 是不是也可以进入房间,打断 A 在房间里的隐私。这个就是不具备原子性的。
那我们应该如何解决这个问题呢?是不是只要给房间加一把锁,A 进去就把门锁上,其他人是不是就进不来了。这样就保证了这段代码的原子性了。
有时也把这个现象叫做同步互斥,表示操作是互相排斥的。
4.内存可见性问题
可见性指, 一个线程对共享变量值的修改,能够及时地被其他线程看到。

import java.time.LocalDateTime;

/**
 * 内存可见性问题
 */
public class ThreadDemo17 {
    //全局的变量
    private static  boolean flag=true;
    public static void main(String[] args) {
        //创建子线程1
        Thread t1=new Thread(()->{
            System.out.println("线程1开始执行:"+ LocalDateTime.now());
            while(flag){
 
            }
            System.out.println("线程1结束执行!"+LocalDateTime.now());
        });
        t1.start();

        Thread t2=new Thread(()->{
            //休眠1s
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程2:修改flag=false"+LocalDateTime.now());
            flag=false;
        });
        t2.start();
    }
}

线程1一直在执行,他并没有感知到全局变量flag的变化,这就是内存可见性问题(因为线程2早已把全局变量flag修改成另一个值了)。
5.指令重排序
编译器优化的本质是调整代码的执行顺序,在单线程下没问题,但在多线程下容易出现混乱,从而造成线程安全问题。

volatile

牺牲性能
volatile可以解决内存可见性问题和指令重排序问题,不能解决原子性问题
代码在写入 volatile 修饰的变量的时候:
1.改变线程工作内存中volatile变量副本的值
2.将改变后的副本的值从工作内存刷新到主内存
代码在读取 volatile 修饰的变量的时候:
1.从主内存中读取volatile变量的最新值到线程的工作内存中
2. 从工作内存中读取volatile变量的副本

import java.time.LocalDateTime;

/**
 * 解决内存可见性问题
 */
public class ThreadDemo17 {
    //全局的变量
    private static volatile boolean flag=true;//加入volatile
    public static void main(String[] args) {
        //创建子线程1
        Thread t1=new Thread(()->{
            System.out.println("线程1开始执行:"+ LocalDateTime.now());
            while(flag){

            }
            System.out.println("线程1结束执行!"+LocalDateTime.now());
        });
        t1.start();

        Thread t2=new Thread(()->{
            //休眠1s
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程2:修改flag=false"+LocalDateTime.now());
            flag=false;
        });
        t2.start();
    }
}

在这里插入图片描述

使用volatile并不能完全解决线程安全问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值