淺析Java 并發(fā)編程中的synchronized
synchronized關(guān)鍵字,我們一般稱之為“同步鎖”,用它來修飾需要同步的方法和需要同步代碼塊,默認(rèn)是當(dāng)前對(duì)象作為鎖的對(duì)象。在用synchronized修飾類時(shí)(或者修飾靜態(tài)方法),默認(rèn)是當(dāng)前類的Class對(duì)象作為鎖的對(duì)象,故存在著方法鎖、對(duì)象鎖、類鎖這樣的概念。
一、沒有設(shè)置線程同步的情況
先給出以下代碼感受下代碼執(zhí)行的時(shí)候?yàn)槭裁葱枰剑看a可能比較枯燥,配上業(yè)務(wù)理解起來就會(huì)舒服很多,學(xué)生軍訓(xùn),有三列,每列5人,需要報(bào)數(shù),每個(gè)線程負(fù)責(zé)每一列報(bào)數(shù)。
class SynchronizedExample {
protected static int num = 0;
protected void numberOff() {
for(int i=0; i<5; i++) {
num++;
System.out.println(Thread.currentThread().getName()+":"+SynchronizedExample.num);
}
}
}
public class SynchronizedTest {
public static void main(String[] args) throws InterruptedException {
SynchronizedExample se = new SynchronizedExample();
for(int i=1; i<=3; i++) {
new Thread( ()-> {se.numberOff();}, "線程"+i).start();
}
}
}
執(zhí)行結(jié)果如下:
線程1:1
線程2:2
線程1:3
線程3:4
.......
之所以出現(xiàn)這種情況,是因?yàn)槿齻€(gè)線程是異步的,沒有同步。
對(duì)應(yīng)的業(yè)務(wù)場(chǎng)景就是,在第一列沒有完成報(bào)數(shù)的時(shí)候,其他隊(duì)列搶報(bào)了,這在現(xiàn)實(shí)中是不允許的,所以需要類似于synchronized等具有同步功能的關(guān)鍵字粉末登場(chǎng)。
二、方法同步鎖
當(dāng)報(bào)數(shù)方法加上synchronized關(guān)鍵字之后,就會(huì)一列一列的報(bào)數(shù)。
protected synchronized void numberOff() {
for(int i=0; i<5; i++) {
num++;
System.out.println(Thread.currentThread().getName()+":"+SynchronizedExample.num);
}
}
執(zhí)行結(jié)果如下:
線程1:1
線程1:2
線程1:3
線程1:4
......
寫到這里還是要從技術(shù)層面講下原理,當(dāng)一個(gè)線程執(zhí)行帶有synchronized關(guān)鍵字的方法時(shí),該線程會(huì)在該方法處設(shè)置一個(gè)鎖(其他線程打不開這個(gè)鎖,只能在外邊等該線程釋放掉該鎖,一般都是執(zhí)行完所有代碼后主動(dòng)釋放鎖),表示此方法是當(dāng)前線程獨(dú)占的,對(duì)應(yīng)到上述業(yè)務(wù)中就是一次只能有一個(gè)隊(duì)列報(bào)數(shù)。
三、對(duì)象鎖
改進(jìn)后的代碼用到了一個(gè)對(duì)象鎖,該對(duì)象鎖默認(rèn)是當(dāng)前對(duì)象,上述代碼等同于以下代碼:
protected void numberOff() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
num++;
System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
}
}
}
當(dāng)多個(gè)線程用一個(gè)對(duì)象鎖,各個(gè)線程可以達(dá)到同步的作用,如果每個(gè)線程都用自己的對(duì)象鎖,那么synchronized就失去了同步的作用。如以下代碼:
class SynchronizedExample {
protected static int num = 0;
protected void numberOff() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
num++;
System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
}
}
}
}
public class SynchronizedTest {
public static void main(String[] args) throws InterruptedException {
SynchronizedExample se = new SynchronizedExample();
for(int i=1; i<=3; i++) {
new Thread( ()-> {new SynchronizedExample().numberOff();}, "隊(duì)列"+i).start();
}
}
}
執(zhí)行結(jié)果如下:
線程1:1
線程2:2
線程1:3
線程3:4
.......
有讀者會(huì)說不同線程執(zhí)行的是不同對(duì)象中的方法,肯定達(dá)不到同步的效果,也對(duì),也很有道理,接著看如下代碼:
class SynchronizedExample {
protected static int num = 0;
protected void numberOff(Object lock) {
synchronized (lock) {
for (int i = 0; i < 5; i++) {
num++;
System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
}
}
}
}
public class SynchronizedTest {
public static void main(String[] args) throws InterruptedException {
SynchronizedExample se = new SynchronizedExample();
for(int i=1; i<=3; i++) {
new Thread( ()-> {se.numberOff(new Object());}, "隊(duì)列"+i).start();
}
}
}
執(zhí)行結(jié)果如下:
線程1:1
線程2:2
線程1:3
線程3:4
.......
四、類鎖
對(duì)于上述問題,讀者應(yīng)該得出一個(gè)結(jié)論,要想達(dá)到同步的效果,必須用同一個(gè)鎖,此時(shí)類鎖可以粉末登場(chǎng)??慈缦麓a:
protected void numberOff(Object lock) {
synchronized (SynchronizedExample.class) {
for (int i = 0; i < 5; i++) {
num++;
System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
}
}
}
上述代碼可以達(dá)到同步的效果。
五、靜態(tài)鎖
靜態(tài)鎖是針對(duì)靜態(tài)方法而言,當(dāng)一個(gè)靜態(tài)方法中有synchronized關(guān)鍵字時(shí),默認(rèn)的是使用當(dāng)前類字節(jié)碼對(duì)象作為鎖。代碼示例如下:
class SynchronizedExample {
protected static int num = 0;
protected synchronized static void numberOff() {
for (int i = 0; i < 5; i++) {
num++;
System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
}
}
}
public class SynchronizedTest {
public static void main(String[] args) throws InterruptedException {
for (int i = 1; i <= 3; i++) {
new Thread(() -> { new SynchronizedExample().numberOff(); }, "隊(duì)列" + i).start();
}
}
}
六、線程池實(shí)現(xiàn)
最后用線程池將上述代碼寫一下
package ioo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class SynchronizedExample {
protected static int num = 0;
protected synchronized static void numberOff() {
for (int i = 0; i < 5; i++) {
num++;
System.out.println(Thread.currentThread().getName() + ":" + SynchronizedExample.num);
}
}
}
public class SynchronizedTest {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
for(int i=1; i<=3; i++) {
executorService.execute(() -> new SynchronizedExample().numberOff());
}
}
}
以上就是淺析Java 并發(fā)編程中的synchronized的詳細(xì)內(nèi)容,更多關(guān)于Java 并發(fā)編程 synchronized的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Java并發(fā)編程深入理解之Synchronized的使用及底層原理詳解 下
- Java并發(fā)編程深入理解之Synchronized的使用及底層原理詳解 上
- Java并發(fā)之synchronized實(shí)現(xiàn)原理深入理解
- java并發(fā)編程之深入理解Synchronized的使用
- 詳解Java并發(fā)編程之內(nèi)置鎖(synchronized)
- 淺析java并發(fā)中的Synchronized關(guān)鍵詞
- Java并發(fā) synchronized鎖住的內(nèi)容解析
- 詳解java并發(fā)編程(2) --Synchronized與Volatile區(qū)別
- 詳解Java利用同步塊synchronized()保證并發(fā)安全
- java并發(fā)之synchronized
相關(guān)文章
解決Mybatis-Plus更新方法不更新NULL字段的問題
這篇文章主要介紹了解決Mybatis-Plus更新方法不更新NULL字段的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
java基礎(chǔ)之 “==”與“equals”區(qū)別詳解
這篇文章主要介紹了java基礎(chǔ)之 “==”與“equals”區(qū)別詳解,需要的朋友可以參考下2020-02-02
Java基礎(chǔ)之?dāng)?shù)組超詳細(xì)知識(shí)總結(jié)
這篇文章主要介紹了Java基礎(chǔ)之?dāng)?shù)組詳解,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很好的幫助,需要的朋友可以參考下2021-05-05
SpringCloud Gateway 利用 Mysql 實(shí)現(xiàn)動(dòng)態(tài)路由的方法
這篇文章主要介紹了SpringCloud Gateway 利用 Mysql 實(shí)現(xiàn)動(dòng)態(tài)路由的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02
JAVA中StringBuffer與String的區(qū)別解析
這篇文章主要介紹了JAVA中StringBuffer與String的區(qū)別解析,需要的朋友可以參考下2014-02-02
springmvc和js前端的數(shù)據(jù)傳遞和接收方式(兩種)
本文介紹了springmvc和js前端的數(shù)據(jù)傳遞和接收方式(兩種),詳細(xì)的介紹了兩種方式,一種是json格式傳遞,另一種是Map傳遞,具有一定的參考價(jià)值,有興趣的可以了解一下2017-12-12
Java設(shè)計(jì)模式中的策略模式詳細(xì)解析
這篇文章主要介紹了Java設(shè)計(jì)模式中的策略模式詳細(xì)解析,所謂策略模式,指的是做某一件事時(shí)有多種選擇(即策略),且不同的策略之間相互獨(dú)立,而且無論使用哪種策略,得到的結(jié)果都是相同的,需要的朋友可以參考下2023-12-12
Java設(shè)計(jì)模式之觀察者模式(Observer模式)介紹
這篇文章主要介紹了Java設(shè)計(jì)模式之觀察者模式(Observer模式)介紹,Java深入到一定程度,就不可避免的碰到設(shè)計(jì)模式(design pattern)這一概念,了解設(shè)計(jì)模式,將使自己對(duì)java中的接口或抽象類應(yīng)用有更深的理解,需要的朋友可以參考下2015-03-03

