1.多线程运行机制:
1.当一个线程启动后,JVM会为其分配一个独立的 【线程栈区】
这个线程在这个独立的栈区中运行
2.线程的调度就是抢占式
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("小强的第"+(i+1)+"次循环");
}
}
}
public class Tests {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
for (int i = 0; i < 100; i++) {
System.out.println("张三的第"+(i+1)+"次循环");
}
}
}
2.多线程的安全性问题_可见性
多线程的安全性问题-可见性
概述:一个线程没有看见另一个线程对共享变量的修改
比如:先启动一个线程,在线程中将一个变量的值更改,而主线程却一致无法获得变量的值
public class MyThread extends Thread{
//共享变量(主线程和子线程共享)
static boolean flag = false;
@Override
public void run() {
// 休眠5秒
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 修改flag的值
flag = true;
System.out.println("子线程把flag的值修改成了true了");
}
}
public class Tests {
public static void main(String[] args) {
MyThread myThread = new MyThread();
// 启动线程
myThread.start();
while (true){
if (MyThread.flag == true){
System.out.println("结束此循环");
break;
}
}
}
}
期望的结果:
子线程修改共享变量flag的值为true,然后主线程就会结束死循环
实际的结果:
子线程修改共享变量flag的值为true,主线程没有结束死循环
原因:
子线程对共享变量flag修改后的值,主线程时不可见的
由于死循环时非常简单,接近底层的代码,所以只需速度非常的块,来不及区主内存中从新获取新的值,所以主线程工作内存中的flag的值一直都是false
一致死循环,如果某一时刻,主线程去【主内存】中从新获取修改后的flag值,才会结束死循环
但主线程什么时候去主内存中获取修改后的flag的值,我们不确定,所以可能存在多线程可见性问题
主内存:
静态区或者堆内存都称之为主内存,只要不是线程的栈空间,其余内存空间都可以叫做主内存
3.多线程的安全性问题_有序性
4.多线程的安全性问题_原子性
多线程的安全性问题:原子性
概述:所谓原子性 是指 在一次操作或者多次操作中,要么所有的操作全部都得到了执行并且不会受到任何因素的干扰而中断
要么所有的操作都不执行,多个操作时一个不可以分割的整体
演示:一条子线程和一条多线程都对共享变量a进行 ++ 操作,每条线程对 a++操作 100000次
public class MyThread extends Thread{
//共享变量
static int a = 0;
@Override
public void run() {
// 任务:对共享变量a自增10万次
for (int i = 0; i < 100000; i++) {
a++;
}
System.out.println("子线程执行完毕!");
}
}
public class Tests {
/*
* 多线程的安全性问题:原子性
* 概述:所谓原子性 是指 在一次操作或者多次操作中,要么所有的操作全部都得到了执行并且不会受到任何因素的干扰而中断
* 要么所有的操作都不执行,多个操作时一个不可以分割的整体
* 演示:一条子线程和一条多线程都对共享变量a进行 ++ 操作,每条线程对 a++操作 100000次
* */
public static void main(String[] args) {
// 创建线程对象
MyThread myThread = new MyThread();
// 启动线程
myThread.start();
// 主线程对共享变量a自增10万次
for (int i = 0; i < 100000; i++) {
MyThread.a++;
}
// 暂停 保证主线程和子线程都对共享变量a自增完了10万次,在统计a的结果
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 打印最终共享变量a的值
System.out.println("最终"+MyThread.a);
}
}
期望的结果: 最终a的值是 200000
原因:两个线程对共享变量的操作 产生了 覆盖的效果