4.2.3 代码的重排序
如果在单线程情况下,JVM和CPU指令集 都会对代码进行优化(重排序)
重排序优化方案 会保证线程内代码执行的依赖关系
4.3 线程安全
使用 synchronized
关键字
synchronized 语法使用
1.静态方法
2.实例方法
3.代码块
synchronized(对象){
....
}
// Java的一个类也是一个对象
// 类名.class
synchronized
用的锁是存在Java对象对象里面的
进入synchronized
代码行时 需要获取对象锁
1.获取成功:往下执行代码
2.获取失败:造成阻塞 线程挂起
退出synchronized
代码块 或synchronized
方法
1.退回对象锁
2.通知JVM及系统,其他线程可以来竞争这把锁
public class SafeThread {
public static final int COUNT = 10000;
public static final int NUM = 20;
public static int a = 0;
public static void main(String[] args) {
for (int i = 0; i < NUM; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < COUNT; j++) {
// 用this 是指给Runnable对象进行加锁
// 不能达到线程安全
// 加锁的是每个线程内自己的锁
/*synchronized(this){
a++;
}*/
synchronized (SafeThread.class){
a++;
}
// create(a);
}
}
}).start();
}
while (Thread.activeCount()>1) {
Thread.yield();
}
System.out.println(a);
}
// SafeThread.class 加锁
public static synchronized void create(int n){
n++;
}
// new SafeThread() 加锁 this
public synchronized void create2(int n){
n++;
}
}
唤醒是JVM和系统级别,程序还是阻塞的
运行的线程数量越多,性能下降的越快(归还对象锁的时候,有越多的线程不停的在唤醒、阻塞之间切换)
对于synchronized
内的代码来说,在同一时间点,只有一个线程在运行(没有并发、并行)
同步代码执行时间越短,性能下降快
synchronized
怎么保证线程安全?
是通过同步互斥达到的
因为对同一个对象锁对同一个对象进行加锁的操作,然后让其他线程不能够执行,而且对于synchronized
内的代码来说,在同一时间点,只有一个线程在运行,对于其他代码都是互斥的,这样线程就满足了线程安全的三大特性,就达到了线程安全,运行的线程数量越多,性能就下降的越快,因为归还对象锁的时候,有越多的线程不停的在唤醒、阻塞之间切换
volatile关键字
- 修饰的共享变量,只能保证可见性和有序性 不能保证原子性
- 不能使用在局部变量上
- 可以使用在成员变量或者静态类变量
- 被
volatile
修饰的变量,进行赋值操作时,可以依赖常量,不能依赖变量,如果依赖变量,会造成线程不安全(不能保证原子性) volatile
可以结合线程加锁的一些手段,可以提高效率- 进行变量的读取或者常量赋值运算时,可以不用进行加锁