鎖概述
鎖是Java中除了AtomicXXX類之外,另一種實現(xiàn)原子性的方式,典型的兩種基于鎖實現(xiàn)原子性的方式是synchronized關鍵字和基于Lock接口的實現(xiàn)類;
synchronized關鍵字加鎖
- 依賴于JVM的鎖實現(xiàn),用synchronized關鍵字加鎖;
- synchronized關鍵字加的鎖是不可中斷鎖,適合競爭不激烈,可讀性好;
- synchronized關鍵字加的鎖在競爭激烈時性能下降的非常快;
Lock接口的實現(xiàn)類
- 依賴于特殊的CPU指令,比如JDK中的java.util.concurrent.locks.Lock接口,比較有代表性的實現(xiàn)類有ReentrantLock;
- Lock接口的實現(xiàn)類加的鎖是可中斷鎖,競爭激烈時能維持常態(tài);
synchronized能修飾的四種對象
- 修飾代碼塊:被修飾的代碼稱作同步語句塊,其作用范圍是大括號括起來的代碼,作用于調用的對象(可以自己指定鎖定對象);如果代碼塊就是整個方法體,那么和修飾方式是等同的;
- 修飾方法:被修飾的方法稱為同步方法,作用范圍是整個方法,作用于調用的對象(this);
- 修飾靜態(tài)方法:作用范圍是整個靜態(tài)方法,作用于這個類的所有對象,本質是對 Class 對象上鎖;
- 修飾類:作用范圍是synchronized后面的括號括起來的部分,作用于這個類的所有對象,本質是對 Class 對象上鎖;
synchronized修飾代碼塊示例 01 - 正例
- 同一個對象在不同線程中訪問同步代碼塊,同步代碼塊對同一個調用對象是能起到同步作用的;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j
public class SynchronizedCodeBlock {
public void test1(int j) {
synchronized (this) {
for (int i = 0; i < 10; i++) {
log.info("synchronized block object {} - {}", j, i);
}
}
}
public static void main(String[] args) {
testCodeBlockSync();
}
private static void testCodeBlockSync() {
SynchronizedCodeBlock example1 = new SynchronizedCodeBlock();
ExecutorService service = Executors.newCachedThreadPool();
service.execute(() -> {
example1.test1(1);
});
service.execute(() -> {
example1.test1(1);
});
}
}
輸出:
- 同一個對象所在的2個線程按順序先后執(zhí)行;
17:06:51.597 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 0
17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 1
17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 2
17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 3
17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 4
17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 5
17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 6
17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 7
17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 8
17:06:51.602 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 9
17:06:51.602 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 0
17:06:51.602 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 1
17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 2
17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 3
17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 4
17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 5
17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 6
17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 7
17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 8
17:06:51.603 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 9
synchronized修飾代碼塊示例 02 - 反例
- 不同對象在不同線程中訪問同步代碼塊,同步代碼塊對不同調用對象是不能起到同步作用的;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Slf4j
public class SynchronizedCodeBlock {
public void test1(int j) {
synchronized (this) {
for (int i = 0; i < 10; i++) {
log.info("synchronized block object {} - {}", j, i);
}
}
}
public static void main(String[] args) {
testCodeBlockNotSync();
}
private static void testCodeBlockNotSync() {
SynchronizedCodeBlock example1 = new SynchronizedCodeBlock();
SynchronizedCodeBlock example2 = new SynchronizedCodeBlock();
ExecutorService service = Executors.newCachedThreadPool();
service.execute(() -> {
example1.test1(1);
});
service.execute(() -> {
example2.test1(2);
});
}
}
輸出:
- 亂序的,兩個對象所在的線程同時執(zhí)行;
17:07:52.278 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 0
17:07:52.278 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 0
17:07:52.284 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 1
17:07:52.284 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 1
17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 2
17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 2
17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 3
17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 3
17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 4
17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 4
17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 5
17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 6
17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 7
17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 5
17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 8
17:07:52.285 [pool-1-thread-1] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 1 - 9
17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 6
17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 7
17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 8
17:07:52.285 [pool-1-thread-2] INFO com.example.concurrency.example.SynchronizedCodeBlock - synchronized block object 2 - 9
synchronized修飾代碼塊示例 03 - run() 方法中的 this 是誰?
- 答案:是 new Thread(instance) 中的 instance;
- SynchronizedCodeBlock02 的 run() 方法對 this 加鎖,創(chuàng)建 t1 和 t2 傳入的 Runnable 都是 instance,故線程 t1 和 t2 都是對 instance 加鎖,所以 t1 和 t2 的執(zhí)行可以同步;
package com.example.concurrency.example.sync;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SynchronizedCodeBlock02 implements Runnable{
static SynchronizedCodeBlock02 instance = new SynchronizedCodeBlock02();
@Override
public void run() {
synchronized (this) {
log.info("{} start",Thread.currentThread());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("{} end",Thread.currentThread());
}
}
public static void main(String[] args) {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
while (t1.isAlive() || t2.isAlive()) {
}
log.info("{} end", Thread.currentThread());
}
}
輸出:
21:50:16.719 [Thread-0] INFO com.example.concurrency.example.sync.SynchronizedCodeBlock02 - Thread[Thread-0,5,main] start
21:50:19.725 [Thread-0] INFO com.example.concurrency.example.sync.SynchronizedCodeBlock02 - Thread[Thread-0,5,main] end
21:50:19.725 [Thread-1] INFO com.example.concurrency.example.sync.SynchronizedCodeBlock02 - Thread[Thread-1,5,main] start
21:50:22.725 [Thread-1] INFO com.example.concurrency.example.sync.SynchronizedCodeBlock02 - Thread[Thread-1,5,main] end
21:50:22.725 [main] INFO com.example.concurrency.example.sync.SynchronizedCodeBlock02 - Thread[main,5,main] end