线程的状态一共是6个
new
尚未启动
runable
运行状态 runnable 正在运行的时候 被wait join locksupport.park方法进行等待后 编程waiting 状态 在被notify 或者notifyall 或者locksupport.unpack 唤醒 编程runable
blocked
堵塞 等待锁为堵塞 当获得锁后从此状态脱离
Teminated
88状态
Time_waiting
被sleep。或者wait加上时间后 进入此状态 时间结束 则进入runable 状态
waiting
等待状态
关键字 synchronized volatile
synchronized
在多线程同一资源进行访问的时候 进行上锁操作
原子性和可见性
上代码
public class SyTest implements Runnable {
int count = 0;
@Override
public void run() {
count++;
System.out.println(Thread.currentThread().getName() + " count==" + count);
}
public static void main(String[] args) {
// 关键字 synchronized 的验证 可见性和原子性
// 比如数 在多个线程里进行增加 A线程可以对数进行更改 B 也可以 那么 A B 都不知道其改动的结果 会出现问题
SyTest syTest = new SyTest();
for (int i = 0; i < 100; i++) {
//创建线程 对其进行自增操作 增加100次
new Thread(syTest, "name" + i).start();
}
}
}
结果会出现如图的错误
50 多加了2次 并且直接46 到50
那么可以给run 方法添加关键字synchronized 把方法锁上。另外一个线程进入前 要去看看锁的状态 如果是同一个线程 那么其锁的重入属性,是可以直接进入。如果资源已经被其他线程使用中 则开始进行自旋,等待,或者进行锁升级 或者自旋期间锁释放后使用资源
synchronized 现在是锁升级。一开始偏向锁 比如有个空间 C 就是锁的记录空间 我一个线程D进来了,会先去C中看看,无值,代表这个线程D是第一个使用的,记录下来。 有值,判断是不是值一致,一致放行,不一致,查看锁的状态。如果已经释放了,那么进入,记录,如果没有释放,还有资源占用,线程D进行自旋,自旋等待锁释放,如果10次后锁还是被占用 升级为重量级的os。
更改后的代码
public class SyTest implements Runnable {
int count = 0;
@Override
public synchronized void run() {
count++;
System.out.println(Thread.currentThread().getName() + " count==" + count);
}
public static void main(String[] args) {
// 关键字 synchronized 的验证 可见性和原子性
// 比如数 在多个线程里进行增加 A线程可以对数进行更改 B 也可以 那么 A B 都不知道其改动的结果 会出现问题
SyTest syTest = new SyTest();
for (int i = 0; i < 100; i++) {
//创建线程 对其进行自增操作 增加100次
new Thread(syTest, "name" + i).start();
}
}
}
volatile
保证线程的可见性
比如 有个线程A 和其他线程对一个资源都要进行更改,那么volatile
使用的是缓存一致性协议 当A 做了更改资源 不仅回写 而且告诉其他使用的资源无效了 资源进行了更改的时候 发现无效 则去重新获取
禁止指令重排序
指令重排序 在运行的时候 编译器或者处理器会对代码进行重新的排序
为了更好的优化 或者提高cpu的使用率
上代码
public class Testvloatile {
//e
final static private Testvloatile testvloatile = new Testvloatile();
public static Testvloatile getTestvloatile() {
return testvloatile;
}
}
class Testvloatile02 {
//b
static private Testvloatile testvloatile02 = null;
public static synchronized Testvloatile getTestvloatile02() {
if (testvloatile02 == null) {
testvloatile02 = new Testvloatile();
}
return testvloatile02;
}
}
class Testvloatile03 {
//b
static private volatile Testvloatile testvloatile03 = null;
public static Testvloatile getTestvloatile03() {
if (testvloatile03 == null) {
synchronized (Testvloatile03.class) {
if (testvloatile03 == null) {
testvloatile03 = new Testvloatile();
}
}
}
return testvloatile03;
}
}
1)饿汉式单例模式的写法:线程安全
2)懒汉式单例模式的写法:非线程安全
3)双检锁单例模式的写法:线程安全 ➕ volatile 线程安全
主要是三个层面保证禁止重排序
1.ACC_VOLATILE标记
2.内存屏障 4种 在读到ACC_VOLATILE标记时会在内存区读写之前都加屏障。
3.看到读写屏障后 使用lock指令,在指令前后都加lock(屏障),保证前后不乱序。