目录
1. synchronized基本使用
synchronized 的基本⽤法有以下 3 种:
1. 修饰静态⽅法
2. 修饰普通⽅法
3. 修饰代码块
synchronized 修饰静态方法
public class ThreadSynchronized1 {
private static int number = 0;
static class Counter {
private static int MAX_COUNT = 1000000;
public synchronized static void incr() {
for (int i = 0; i < MAX_COUNT; i++) {
number++;
}
}
public synchronized static void decr() {
for (int i = 0; i < MAX_COUNT; i++) {
number--;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
Counter.incr();
});
t1.start();
Thread t2 = new Thread(() -> {
Counter.decr();
});
t2.start();
t1.join();
t2.join();
System.out.println("最终的结果:" + number);
}
}
输出:
最终的结果:0
synchronized 修饰普通方法
public class ThreadSynchronized2 {
private static int number = 0;
static class Counter {
private static int MAX_COUNT = 1000000;
public synchronized void incr() {
for (int i = 0; i < MAX_COUNT; i++) {
number++;
}
}
public synchronized void decr() {
for (int i = 0; i < MAX_COUNT; i++) {
number--;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
Counter.incr();
});
t1.start();
Thread t2 = new Thread(() -> {
Counter.decr();
});
t2.start();
t1.join();
t2.join();
System.out.println("最终的结果:" + number);
}
}
输出:
最终的结果:0
synchronized 修饰代码
public class ThreadSynchronized3 {
private static int number = 0;
static class Counter {
private static int MAX_COUNT = 1000000;
private Object myLock = new Object();
public void incr() {
for (int i = 0; i < MAX_COUNT; i++) {
synchronized (myLock) {
number++;
}
}
}
public void decr() {
for (int i = 0; i < MAX_COUNT; i++) {
synchronized (myLock) {
number--;
}
}
}
public static void test() {
synchronized (Counter.class){
}
}
}
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
counter.incr();
});
t1.start();
Thread t2 = new Thread(() -> {
counter.decr();
});
t2.start();
t1.join();
t2.join();
System.out.println("最终的结果:" + number);
}
}
输出:
最终的结果:0
2. synchronized特征
a. 互斥性(排他性)
synchronized 会起到互斥效果, 某个线程执⾏到某个对象的 synchronized 中时, 其他线程如果也
执⾏到同⼀个对象 synchronized 就会阻塞等待.
●进⼊ synchronized 修饰的代码块, 相当于 加锁
● 退出 synchronized 修饰的代码块, 相当于 解锁
synchronized用的锁是存在Java对象头里的
假设有 A B C 三个线程, 线程 A 先获取到锁, 然后 B 尝试获取锁, 然后 C 再尝试获取锁, 此时
B 和 C 都在阻塞队列中排队等待. 但是当 A 释放锁之后, 虽然 B ⽐ C 先来的, 但是 B 不⼀定就
能获取到锁, ⽽是和 C 重新竞争, 并不遵守先来后到的规则.
b. 刷新内存(内存可见性问题)
synchronized 的⼯作过程:
1. 获得互斥锁
2. 从主内存拷⻉变量的最新副本到⼯作的内存
3. 执⾏代码
4. 将更改后的共享变量的值刷新到主内存
5. 释放互斥锁
所以 synchronized 也能保证内存可⻅性。
c. 可重入
synchronized 可重入性测试
public class ThreadSynchronized4 {
public static void main(String[] args) {
synchronized (ThreadSynchronized4.class) {
System.out.println("当前主线程已经得到了锁");
synchronized (ThreadSynchronized4.class) {
System.out.println("当前主线程再次得到了锁");
}
}
}
}
输出:
当前主线程已经得到了锁
当前主线程再次得到了锁
3. 注意事项
a. 加同一把锁
对于同一个·业务·的多个线程加锁对象,一定要是同一个对象(加同一把锁)。
加同一把锁
public class ThreadSynchronized5 {
private static final int count = 100000;
static int num = 0;
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
Object obj1 = new Object();
Thread t1 = new Thread(() -> {
synchronized (obj) {
for (int i = 0; i < count; i++) {
num++;
}
}
},"线程1");
t1.start();
Thread t2 = new Thread(() -> {
synchronized (obj) {
for (int i = 0; i < count; i++) {
num--;
}
}
},"线程2");
t2.start();
t1.join();
t2.join();
System.out.println("最终运行结果:" + num);
}
}
输出:
最终运行结果:0
b. 实例类可以使用this,静态类使用xxx.class
synchronized修饰代码块,代码块在静态方法中不能使用this对象。
ms:synchronized是如何实现的?
答:JVM层面synchronized是依靠监视器Monitor实现的;从操作系统层面来看,synchronized是基于操作系统的互斥锁(Mutex)来实现。
JDK1.6之前Synchronized默认是使用重量级锁实现,所以性能比较差。
synchronized 1.6优化:
(无人访问时)无锁 -->(有人访问)偏向锁 -->(多个线程竞争)轻量级锁 --> 重量级锁