synchronized
对象锁,采用互斥的方式让同一时刻至多有一个线程能持有「对象锁」。
其他锁想要获取这个「对象锁」就会被阻塞住。
需要注意
- 互斥是保证临界区的竞态条件发生,同一时刻只能有一个线程执行临界区代码
- 同步是由于线程的执行顺序
对象锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| package com.redisc;
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.Test") public class Test {
static int counter = 0; static Object Lock = new Object();
public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { for (int i = 0; i < 5000; i++) { synchronized (Lock) { counter++; } } }); Thread t2 = new Thread(() -> { for (int i = 0; i < 5000; i++) { synchronized (Lock) { counter--; } } });
t1.start(); t2.start(); t1.join(); t2.join();
log.debug("{}", counter); } }
|
输出
1
| 17:45:38.434 [main] DEBUG c.Test - 0
|
使用 synchronized
加锁对象后,任何一个线程在处理临界对象的时候,都需要先请求对象锁。
synchronized
实际上是用对象锁保证了临界区内代码的原子性。临界区内的代码对外是不可分隔的。
面向对象的锁的改进
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| package com.redisc;
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.Test") public class Test {
public static void main(String[] args) throws InterruptedException { Room room = new Room(); Thread t1 = new Thread(() -> { for (int i = 0; i < 5000; i++) { room.decrement(); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < 5000; i++) { room.increment(); } });
t1.start(); t2.start(); t1.join(); t2.join();
log.debug("{}", room.getCounter()); } }
class Room { private int counter = 0;
public void increment() { synchronized (this) { counter++; } }
public void decrement() { synchronized (this) { counter--; } }
public int getCounter() { synchronized (this) { return this.counter; } } }
|
输出
1
| 21:51:10.538 [main] DEBUG c.Test - 0
|
加在方法
对象方法
加在对象方法上,锁定的是 this。
语法如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Test{ public synchronized void test(){
} }
等价于
class Test{ public void test(){ synchronized(this){
} } }
|
例子如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package com.redisc;
import lombok.extern.slf4j.Slf4j;
@Slf4j(topic = "c.Test") public class Test {
public static void main(String[] args) throws InterruptedException { Room room = new Room(); Thread t1 = new Thread(() -> { for (int i = 0; i < 5000; i++) { room.decrement(); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < 5000; i++) { room.increment(); } });
t1.start(); t2.start(); t1.join(); t2.join();
log.debug("{}", room.getCounter()); } }
class Room { private int counter = 0;
public synchronized void increment() { counter++; }
public synchronized void decrement() { counter--; }
public synchronized int getCounter() { return this.counter; } }
|
输出
1
| 21:55:41.435 [main] DEBUG c.Test - 0
|
静态方法
语法
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Test{ public synchronized static void test(){
} } 等价于 class Test{ public static void test(){ synchronized(Test.class){
} } }
|