线程状态
6个状态定义;
1.New:尚未启动的线程的线程状态
Thread thread = new Thread();
2.Runnable:可运行线程的线程状态,等待CPU调度。
thread.start();
3.Blocked:线程阻塞等待监视器锁定的线程状态。处于synchronized同步代码块或非法中被阻塞。
4.Waiting:线程等待的线程状态。不带timeout参数的方式调用
Object.wait、LockSupport.join、LockSupport.park.
5.Timed Waiting:具有指定等待时间的等待线程的线程状态、下列带超时的方式:
Thread.sleep、Object.wait、Thread.join、LockSupport.parkNanos、LockSupport.parkUntil
6.Terminated:终止线程的线程状态。线程正常完成执行或者出现异常。
终止线程
1.stop方法
public class Demo1 {
public static void main(String[] args) throws Exception {
MyThread my = new MyThread();
my.start();
my.sleep(1000);
//stop方法
//my.stop();
//interrupt方法
my.interrupt();
while(my.isAlive()) {}
my.point();
}
}
class MyThread extends Thread{
private int i = 0, j = 0;
@Override
public void run() {
synchronized (this){
++i;
try {
Thread.sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
++j;
}
System.out.println("被释放");
}
public void point() {
System.out.println("i:" + i);
System.out.println("j:" + j);
}
}
结果
stop方法破坏了原子性,被废弃了还有interrupt方法结果
不会破坏原子性标志位方法 在while方法中
public class Demo2 {
public volatile static boolean flag = true;
public static void main(String[] args) throws InterruptedException{
new Thread(()->{
try {
while(flag) {
System.out.println("运行中");
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(3000);
flag = false;
System.out.println("释放了");
}
}
线程封闭
多线程访问共享可变数时,涉及到线程间的数据同步的问题。
ThreadLocal来实现
线程级别变量,每个线程都有一个ThreadLocal就是每个线程都拥有了自己独立的一个变量,竞争条件被消除,在并发模式下是绝对安全的变量。 用法ThreadLocal threadLocal = new ThreadLocal<>();
public class Demo3 {
public static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
new Thread(()->{
threadLocal.set("21312312");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadLocal.get());
}).start();
new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadLocal.get());
}).start();
}
}
栈封闭
局部变量的固有属性之一就是封闭在线程中。它们位于执行线程的栈中,其他线程无法访问这个栈。
CPU缓存和内存屏障
CPU高速缓存中的数据是内存中的一小部分,但这一小部分是短时间内CPU即将访问的,当CPU存在大量访问时,可以从Cache中拿。
多级缓存
L1 Cache是CPU第一次高速缓存,她的容量非常小,一般为32-256KB,提高容量所带来的技术难度增加和成本增加非常大
L2 由于L1高速缓存的容量限制,为了再次提高CPU的运算速度,在CPU外部放置一高速存储器,即二级缓存,现在家庭用CPU容量最大的是4MB,而服务器和工作站上用CPU的L2高速缓存普遍大于4MB,有的高达8MB或者16MB。
L3 现在一般都是内置的。在拥有三级缓存的CPU中,只有约5%的数据需要从内存中调用,进 一步提升了CPU效率,同时提升大数据量计算时处理器的性能。具有较大L3缓存的处理器提供 更有效的文件系统缓存行为及较短消息和处理器队列长度。一般是多核共享一个L3缓存!
CPU在读取数据时,先在L1中寻找,再从L2寻找,再从L3寻找,然后是内存,再后是外存储器。
缓存同步协议
多CPU读取同样的数据进行缓存,进行不同运算之后,最终写入主内存以哪个CPU为准?
在这种高速缓存回写的场景下,有一个缓存一致性协议(MESI协议)多数CPU厂商对它 进行了实现。
多处理器时,单个CPU对缓存中数据进行了改动,需要通知给其他CPU。也就是意味着,CPU处理要控制自己的读写操作,还要监听其他CPU发出的通知,从而保证最终一致。
CPU性能优化手段-运行时指令重拍
指令重排的场景:当CPU写缓存时发现缓存区块正被其他CPU占用,为了提高CPU处理性能,可 能将后面的读缓存命令优先执行。
// 代码
x = 100;
y = z;
// 正常执行的三步骤
1、 将100写入x
2、 读取z的值
3、 将z值写入y
// 重排序后执行
1、读取z的值
2、将z值写入y
3、将100写入x
as-if-serial语义:指令重排时,不管怎么重排序,单个线程的执行结果不能被改变。 换句话说,编译器和处理器不会对存在数据依赖关系的操作做重排序。
1、 CPU高速缓存下有一个问题: 缓存中的数据与主内存的数据并不是实时同步的,各CPU(或CPU核心)间缓存的数据也不是 实时同步。在同一个时间点,各CPU所看到同一内存地址的数据的值可能是不一致的。
2、 CPU执行指令重排序优化下有一个问题: 虽然遵守了as-if-serial语义,单仅在单CPU自己执行的情况下能保证结果正确。 多核多线程中,指令逻辑无法分辨因果关联,可能出现乱序执行,导致程序运行结果错误
内存屏障
处理器提供了两个内存屏障指令(Memory Barrier)用于解决上述两个问题:
写内存屏障(Store Memory Barrier):在写指令后插入Store Barrier,能让写入缓存中的 最新数据更新写入主内存,让其他线程可见。 强制写入主内存,这种显示调用,CPU就不会因为性能考虑而去对指令重排。
读内存屏障(Load Memory Barrier):在读指令前插入Load Barrier,可以让高速缓存中的 数据失效,强制从新从主内存加载数据。 强制读取主内存内容,让CPU缓存与主内存保持一致,避免了缓存导致的一致性问题