
public class SyncDemo {
private static int count = 0;
public static void increment() {
count++;
}
public static void decrement() {
count--;
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
increment();
}
}, "t1");
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
decrement();
}
}, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(count);
}
}
问题分析
Java 中对静态变量的自增,自减并不是原子 *** 作。 i++的JVM 字节码指令
getstatic i // 获取静态变量i的值iconst_1 // 将int常量1压入 *** 作数栈iadd // 自增 i–的JVM 字节码指令
getstatic i // 获取静态变量i的值iconst_1 // 将int常量1压入 *** 作数栈isub // 自减 临界区( Critical Section)
我们知道一个程序可以运行多个线程是没有任何问题的。但是多个线程去读共享资源,也是没有问题的!在多个线程对共享资源读写 *** 作时发生指令交错,就会出现问题!一段代码块内如果存在对共享资源的多线程读写 *** 作,称这段代码块为临界区,其共享资源为临界资源。往简单说,上面的i-- 与 i++ 的代码块就是临界区。 竞态条件( Race Condition )
多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件。阻塞式的解决方案:synchronized,Lock非阻塞式的解决方案:原子变量 synchronized解决结果不为0的问题
第一种方式
public synchronized static void increment() {
count++;
}
public static synchronized void decrement() {
count--;
}
第二种方式
private static String lock = "";
public static void increment() {
synchronized (lock) {
count++;
}
}
public static void decrement() {
synchronized (lock) {
count--;
}
}
不同位置的synchronized有什么区别呢?
结束语
本文只说synchronized的基础使用。深入研究请关注后面的文章!synchronized底层原理:Monitor(管程/监视器)从对象在内存布局的布局上深入了解synchronized的各种锁(锁粗化(Lock Coarsening)、锁消除(Lock Elimination)、轻量级锁(Lightweight Locking)、偏向锁(Biased Locking)、自适应自旋(Adaptive Spinning))优化原理为什么synchronized的性能能与Lock持平?锁的优化! 结束语
获取更多有价值的文章,让我们一起成为架构师!关注公众号,可以让你对MySQL有非常深入的了解关注公众号,每天持续高效的了解并发编程!这个公众号,无广告!!!每日更新!!!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)