歡迎點(diǎn)贊閱讀,一同學(xué)習(xí)交流,有疑問請留言 。
GitHub上也有開源 JavaHouse,歡迎star
引用
當(dāng)開發(fā)過程中,我們遇到并發(fā)問題。怎么解決?
一種解決方式,簡單粗暴:上鎖。將千軍萬馬都給攔下來,只允許一個人過獨(dú)木橋。書面意思就是將并行的程序變成串行的程序?,F(xiàn)實(shí)的鎖有門鎖、掛鎖和抽屜鎖等等。在Java中,我們的鎖就是synchronized關(guān)鍵字和Lock接口。
synchronized關(guān)鍵字
synchronized也叫同步鎖,是Java里面的關(guān)鍵字。我們可以猜測到synchronized原理也JVM虛擬機(jī)有關(guān)聯(lián)。
synchronized鎖的是對象。對象里面有一個叫做監(jiān)視鎖(monitor)的東西,監(jiān)視鎖依賴操作系統(tǒng)的互斥鎖(Mutex Lock)。操作系統(tǒng)切換線程其實(shí)就是從用戶態(tài)編程核心態(tài)(cpu的兩種狀態(tài))。這個代價有點(diǎn)高,所以synchronized這個重量級鎖后面也引進(jìn)了偏向鎖和輕量級鎖。
加鎖(監(jiān)視鎖monitor)過程分析():
- 當(dāng)monitor的進(jìn)入數(shù)為0,線程A進(jìn)入
- monitor的進(jìn)入數(shù)為1
- 線程B想進(jìn)入該monitor就會被阻塞。
線程A可以重復(fù)進(jìn)入該monitor,所以synchronized是可重入鎖,和Lock實(shí)現(xiàn)的鎖一樣。
- 程序驗(yàn)證
public class SynchronizedTest {
private static int i = 0;
public static void main(String[] args) {
test();
}
public static void test(){
synchronized (SynchronizedTest.class){
synchronized (SynchronizedTest.class){
i++;
}
}
}
}
- 運(yùn)行結(jié)果
程序正常運(yùn)行,沒有報錯
synchronized可以修飾方法以及代碼塊,代碼塊就是上面重入鎖的例子。
- 修飾方法
public class SynchronizedTest {
static int n = 100;
final static CountDownLatch start = new CountDownLatch(n);
private static int i = 0;
public static void main(String[] args) throws InterruptedException {
for (int j = 0; j < n; j++) {
Thread thread = new Thread(new addNoSynchronized());
thread.start();
}
start.await();
System.out.println(i);
}
public static class addSynchronized implements Runnable{
@Override
public void run() {
addSynchronized();
}
public static synchronized void addSynchronized(){
for (int j = 0; j < 1000; j++) {
i++;
}
start.countDown();
}
}
}
- 運(yùn)行結(jié)果
100000
如果去掉 synchronized 關(guān)鍵字的話,運(yùn)行結(jié)果大概率不是 100000,因?yàn)榫€程不安全問題。
Lock接口
一般我們使用 ReentrantLock 類作為重入鎖,實(shí)現(xiàn)Lock接口。
- 使用方法
public class ReentranLockTest {
private static int j;
private static int n = 100;
private static CountDownLatch latch = new CountDownLatch(n);
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < n; i++) {
new Thread(new LockTest()).start();
}
latch.await();
System.out.println("結(jié)果為:"+j);
}
public static class LockTest implements Runnable{
static Lock lock = new ReentrantLock();
@Override
public void run() {
lockTest();
latch.countDown();
}
private void lockTest() {
lock.lock();
try {
for (int i = 0; i < 1000; i++) {
j++;
}
}finally {
lock.unlock();
}
}
}
}
- 運(yùn)行結(jié)果
結(jié)果為:100000
這里我們鎖住的 j++ 這塊資源區(qū)(公共資源),lock 是 static 關(guān)鍵字修飾的,是類對象,思考一下如果不是類對象會怎么樣?那就是連環(huán)鎖了(看圖)。文章來源:http://www.zghlxwxcb.cn/news/detail-711316.html
每一個線程都對可以用鑰匙解開這把鎖,對于程序而言,加鎖操作就沒有意義了。因?yàn)槲覀冃枰氖且粋€鎖。文章來源地址http://www.zghlxwxcb.cn/news/detail-711316.html
歡迎關(guān)注我的微信公眾號
到了這里,關(guān)于Java并發(fā)之synchronized關(guān)鍵字和Lock接口的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!