🍎一.多线程状态
🍇1.1多线程的状态形式
线程状态 | 说明 |
NEW | 安排了工作, 还未开始行动 |
RUNNABLE | 可工作的. 又可以分成正在工作中和即将开始工作 |
BLOCKED | 这几个都表示排队等着其他事情 |
WAITING | 这几个都表示排队等着其他事情 |
TIMED_WAITING | 这几个都表示排队等着其他事情 |
TERMINATED | 工作完成了 |
1.NEW状态:安排了工作, 还未开始行动
public class Test { public static void main(String[] args) { Thread thread = new Thread(()->{ }); System.out.println(thread.getState()); } }
2.RUNNABLE:可工作的. 又可以分成正在工作中和即将开始工作
public class Test { public static void main(String[] args) { Thread thread = new Thread(()->{ while (true){ //这里面不能有人任务,这样才会显示是就绪状态 } }); thread.start(); System.out.println(thread.getState()); } }
3.TERMINATED:工作完成了
操作系统线程已经执行完毕,线程已经销毁了,但是Thread对象还存在,获取到的状态
public class Test { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(()->{ System.out.println("我滴任务完成啦!"); }); thread.start(); Thread.sleep(500); System.out.println(thread.getState()); } }
4.TIMED_WAITING:代码调用了sleep或者join(超时时间)
public class Test { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(()->{ while (true) { System.out.println("我在等一会"); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); Thread.sleep(500); System.out.println(thread.getState()); } }
BLOCKED,WAITING|这两个状态我们后续会将
🍇1.2状态转化分布图
🍎二.多线程的安全问题
🍇2.1线程安全问题的概念
如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线
程安全的。
如果多线程环境下代码运行的结果是不符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程不安全的。
🍇2.2线程不安全示例
假设我们设置一个count初始值为0,我们使用两个线程同时并且每条线程执行5万次,这样我们的预期count结果为10万,接下来我们来演示一下看看两个线程并发是否安全
public class Test { static class Count{ public int count = 0; public void sum(){ count++; } } public static void main(String[] args) throws InterruptedException { Count count = new Count(); Thread thread1 = new Thread(()->{ for (int i = 0; i < 50000; i++) { count.sum(); } }); Thread thread2 = new Thread(()->{ for (int i = 0; i < 50000; i++) { count.sum(); } }); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println(count.count); } }
我们发现count执行的结果并不是10万,而是5万-10万之间的随机数,这是什么原因呢?接下来我来帮助大家了解一下为什么在对对同一数据进行并发线程不安全
原子性
什么是原子性?
我们把一段代码想象成一个房间,每个线程就是要进入这个房间的人。如果没有任何机制保证,A进入房间之后,还没有出来;B 是不是也可以进入房间,打断 A 在房间里的隐私。这个就是不具备原子性的。
那我们应该如何解决这个问题呢?是不是只要给房间加一把锁,A 进去就把门锁上,其他人是不是就进不来了。这样就保证了这段代码的原子性了。有时也把这个现象叫做同步互斥,表示操作是互相排斥的。
一条 java 语句不一定是原子的,也不一定只是一条指令比如刚才我们看到的 n++,其实是由三步操作组成的:
1. 从内存把数据读到 CPU
2. 进行数据更新
3. 把数据写回到 CPU不保证原子性会给多线程带来什么问题如果一个线程正在对一个变量操作,中途其他线程插入进来了,如果这个操作被打断了,结果就可能是错误的。
可见性
可见性指, 一个线程对共享变量值的修改,能够及时地被其他线程看到.线程之间的共享变量存在 主内存 (Main Memory).每一个线程都有自己的 “工作内存” (Working Memory) .当线程要读取一个共享变量的时候, 会先把变量从主内存拷贝到工作内存, 再从工作内存读取数据.当线程要修改一个共享变量的时候, 也会先修改工作内存中的副本, 再同步回主内存.由于每个线程有自己的工作内存, 这些工作内存中的内容相当于同一个共享变量的 “副本”. 此时修改线程1 的工作内存中的值, 线程2 的工作内存不一定会及时变化.
情况一:
情况二:
情况三:
情况四:
重排序问题: