1. Thread & Runable
先不逼逼,上兩個(gè)例子再說(shuō)。
//栗子1
public class ThreadTest extends Thread {
@Override
public void run() {
//重寫run方法
}
public static void main(String[] args){
Thread t=new ThreadTest ();
t.start();
}
//栗子2
public class RunnableTest implements Runnable{
@Override
public void run() {
//重寫run方法
}
}
public static void main(String[] args) {
RunnableTest r=new RunnableTest();
Thread t=new Thread(r);
t.start();
}
例1,繼承線程類Thread,創(chuàng)建子類ThreadTest,然后new一個(gè)子類對(duì)象,通過(guò)這個(gè)對(duì)象的start方法啟動(dòng)線程;
例2,實(shí)現(xiàn)Runnable接口創(chuàng)建子類,new一個(gè)子類對(duì)象,以這個(gè)子類對(duì)象為參數(shù),new出一個(gè)Thread對(duì)象,最后調(diào)用start方法啟動(dòng)線程。好吧,很簡(jiǎn)單對(duì)吧。直接上干貨。
2 Runable使用
- 注:以下內(nèi)容來(lái)源:http://www.itdecent.cn/p/5483d1689ba8
使用Runnable更具靈活性,可以避免單繼承的局限,并且可以實(shí)現(xiàn)多個(gè)線程同時(shí)處理同一個(gè)資源,同樣還是看例子。
我們就以經(jīng)典的賣票系統(tǒng)講個(gè)故事吧。話說(shuō)有小T(Thread)和小R(Runnable)兩個(gè)票販子,他們手下各有兩個(gè)業(yè)務(wù)員,平常就干著倒賣活動(dòng)門票的活(線程執(zhí)行任務(wù))。有一天,他們各拿到了5張某演唱會(huì)的門票,兩人將售票的任務(wù)交給手下的業(yè)務(wù)員。
小T這邊的業(yè)務(wù)是這樣運(yùn)轉(zhuǎn)的(定義Thread類的子類,重寫run()方法,run()方法即為賣票任務(wù))
public class TicketThread extends Thread {
private int ticket = 5;
private String name;
public TicketThread(String name) {
this.name = name;
}
public void run() {
for (int i = 0; i < 5; i++) {
if (ticket > 0) {
Log.e("T公司",name + "賣了一張票,編號(hào)為t" + (ticket--));
}
}
}
}
業(yè)務(wù)員一大早就開(kāi)始賣票,很快就賣完了(實(shí)例化Thread的子類,調(diào)用start()方法啟動(dòng)該線程)
TicketThread t1 = new TicketThread("1號(hào)業(yè)務(wù)員");
TicketThread t2 = new TicketThread("2號(hào)業(yè)務(wù)員");
t1.start();
t2.start();
兩個(gè)業(yè)務(wù)員賣票結(jié)果如下:
T公司:1號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t5
T公司:2號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t5
T公司:1號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t4
T公司:1號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t3
T公司:2號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t4
T公司:1號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t2
T公司:2號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t3
T公司:1號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t1
T公司:2號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t2
T公司:2號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t1
而小R的業(yè)務(wù)流程則是這樣的(實(shí)現(xiàn)Runnable接口,重寫Runnable的run()方法)
public class TicketRunnable implements Runnable {
private int ticket = 5;
public void run() {
for (int i = 0; i < 5; i++) {
if (ticket > 0) {
Log.e("R公司",Thread.currentThread().getName() + "賣了一張票,編號(hào)為r" + (ticket--));
}
}
}
}
業(yè)務(wù)員同樣很快就把票賣完了(創(chuàng)建Thread子類的實(shí)例,將實(shí)現(xiàn)了Runnable接口的對(duì)象作為參數(shù)實(shí)例化Thread對(duì)象,調(diào)用start()方法啟動(dòng)線程)
TicketRunnable runnable = new TicketRunnable();
Thread r1 = new Thread(runnable, "1號(hào)業(yè)務(wù)員");
Thread r2 = new Thread(runnable, "2號(hào)業(yè)務(wù)員");
r1.start();
r2.start();
兩個(gè)業(yè)務(wù)員賣票結(jié)果如下:
R公司:1號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t5
R公司:2號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t4
R公司:1號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t3
R公司:2號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t2
R公司:1號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為t1
事畢,兩人決定吃個(gè)飯慶祝一下。一番交流后,小R很驚訝小T為啥可以將同樣的票多賣一倍的錢,小T得意地分享了自己的賣票心得:
“因?yàn)槲覍⑵睆?fù)印了一份,這樣我兩個(gè)小弟就可以各拿一份票去兜售了(通過(guò)繼承Thread的方式,當(dāng)新創(chuàng)建一個(gè)線程啟動(dòng)時(shí),其綁定的任務(wù)同樣也新建了一份,這樣他們的任務(wù)是相互獨(dú)立的,自然也無(wú)法實(shí)現(xiàn)資源共享了)”
小R聽(tīng)后感嘆不已:
“竟然還有這種操作?我耿直地將票交給兩個(gè)業(yè)務(wù)員就算了?。▽?shí)現(xiàn)Runnable接口的方式,因?yàn)槎际怯猛粋€(gè)Runnable對(duì)象創(chuàng)建的線程,因此多線程實(shí)際上執(zhí)行的是同一個(gè)任務(wù),這樣也就共享了資源)”
接著小R又問(wèn)小T:“你這么干,事后不怕買到假票的人來(lái)找你?” 小T聽(tīng)后不以為然道:
“怕啥,我們不都是干完一票就跑路的么(線程執(zhí)行完run()方法后會(huì)自行銷毀)”
小R:“我從未見(jiàn)過(guò)有如此厚顏無(wú)恥之人......”
3.1 synchronized使用解析-同步方法(非靜態(tài))
- 注:以下內(nèi)容來(lái)源:http://www.itdecent.cn/p/162cf544b637
小R(Runnable)因?yàn)檎\(chéng)信經(jīng)營(yíng),生意越來(lái)越好了,于是小R便多招了一個(gè)業(yè)務(wù)員。某日,在售出10張門票后不久,小R就收到了顧客的投訴,說(shuō)他們買到了假票。小R懷疑是自己的手下動(dòng)了手腳,便展開(kāi)了調(diào)查:
當(dāng)時(shí)的業(yè)務(wù)流程如下
private class SellTask {
private int ticket = 10;
public void sellTicket(){
if (ticket > 0) {
try{
Thread.sleep(500);
Log.e("R公司",Thread.currentThread().getName() + "賣了一張票,編號(hào)為r" + (ticket--));
}catch (Exception e){
e.printStackTrace();
}
}
}
}
public class TicketRunnable implements Runnable {
SellTask sellTask;
public TicketRunnable(SellTask sellTask){
this.sellTask = sellTask;
}
public void run() {
for (int i = 0; i < 10; i++) {
sellTask.sellTicket();
}
}
}
票交由3個(gè)業(yè)務(wù)員去賣
SellTask sellTask = new SellTask();
TicketRunnable runnable = new TicketRunnable(sellTask);
Thread r1 = new Thread(runnable, "1號(hào)業(yè)務(wù)員");
Thread r2 = new Thread(runnable, "2號(hào)業(yè)務(wù)員");
Thread r3 = new Thread(runnable, "3號(hào)業(yè)務(wù)員");
r1.start();
r2.start();
r3.start();
調(diào)查發(fā)現(xiàn),出現(xiàn)了多個(gè)業(yè)務(wù)員售出編號(hào)相同的票的情況
R公司:1號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為r10
R公司:3號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為r9
R公司:2號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為r8
R公司:1號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為r7
R公司:2號(hào)業(yè)務(wù)員賣了一張票,編號(hào)為r7
...
進(jìn)一步調(diào)查后得知,出現(xiàn)這樣的情況是因?yàn)闃I(yè)務(wù)員答應(yīng)了賣給顧客某編號(hào)的票,并收取了訂金,回頭拿票時(shí)才發(fā)現(xiàn)哥幾個(gè)賣得是同一張票(多個(gè)線程先后操作共享數(shù)據(jù)造成數(shù)據(jù)錯(cuò)誤),沒(méi)辦法只能自己復(fù)制一張給顧客企圖蒙混過(guò)關(guān)。小R不知道該怎么約束自己的手下,遂公開(kāi)招聘能解決問(wèn)題的人。
這天,一位自稱synchronized的男人前來(lái)應(yīng)聘。小R問(wèn)道:“s先生有何高見(jiàn)啊?”s先生淡定地喝了口茶,答道:
“你現(xiàn)在的業(yè)務(wù)流程不太可靠(線程不安全),讓我來(lái)統(tǒng)一管理整個(gè)售票業(yè)務(wù),每一張票的出售都需經(jīng)過(guò)我的審批,一張票賣完后業(yè)務(wù)員才能來(lái)我這再次申請(qǐng)拿票出售,這樣每張票都只能由一個(gè)業(yè)務(wù)員進(jìn)行出售,問(wèn)題也自然解決了(在Java中每一個(gè)對(duì)象都有一個(gè)內(nèi)部鎖,當(dāng)使用synchronized關(guān)鍵字聲明某個(gè)方法時(shí),該方法將受到對(duì)象鎖的保護(hù),這樣一次就只能有一個(gè)線程可以進(jìn)入該方法并獲得該對(duì)象的鎖,其他線程要想調(diào)用該方法,只能排隊(duì)等待。當(dāng)獲得鎖的線程執(zhí)行完該方法并釋放對(duì)象鎖后,別的線程才可拿到鎖進(jìn)入該方法)?!?/p>
小R聽(tīng)后覺(jué)得這方法不錯(cuò),便讓s先生來(lái)試試。這次依然是要出售10張票,業(yè)務(wù)流程經(jīng)過(guò)s先生改進(jìn)后如下
private class SellTask {
private int ticket = 10;
public synchronized void sellTicket(){//使用synchronized聲明sellTicket方法
if (ticket > 0) {
try{
Thread.sleep(500);
Log.e("R公司",Thread.currentThread().getName() + "賣了一張票,編號(hào)為r" + (ticket--));
}catch (Exception e){
e.printStackTrace();
}
}
}
}
與之前的SellTask類相比,該類中使用了synchronized聲明sellTicket()方法。如此一來(lái),問(wèn)題果然解決了,小R懸著的心也終于放了下來(lái)。
3.2 同一個(gè)對(duì)象內(nèi)使用多個(gè)同步方法
某日,小R又開(kāi)始向s先生抱怨起來(lái):“我那幫二愣子手下啊,每次進(jìn)我辦公室匯報(bào)工作都是亂糟糟的,讓他們按順序一個(gè)個(gè)來(lái)就是不聽(tīng),s先生覺(jué)得該如何管管他們???”s先生依然淡定地抿了口茶,說(shuō)道:“不急,容我先看看他們是怎么匯報(bào)的?!毙便依著s先生的意思安排了兩個(gè)手下過(guò)來(lái)匯報(bào)工作。
private class ReportTask {
public void report1(){
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "進(jìn)辦公室");
try{
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "開(kāi)始匯報(bào)");
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "匯報(bào)完畢");
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "出辦公室");
}
public void report2(){
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "進(jìn)辦公室");
try{
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "開(kāi)始匯報(bào)");
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "匯報(bào)完畢");
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "出辦公室");
}
}
public class ReportRunnable1 implements Runnable {
ReportTask task;
public ReportRunnable1(ReportTask task){
this.task = task;
}
public void run() {
task.report1();
}
}
public class ReportRunnable2 implements Runnable {
ReportTask task;
public ReportRunnable2(ReportTask task){
this.task = task;
}
public void run() {
task.report2();
}
}
不一會(huì)兒,兩個(gè)手下前后腳進(jìn)了辦公室,開(kāi)始匯報(bào)
ReportTask reportTask = new ReportTask();
ReportRunnable1 runnable1 = new ReportRunnable1(reportTask);
ReportRunnable2 runnable2 = new ReportRunnable2(reportTask);
Thread r1 = new Thread(runnable1);
Thread r2 = new Thread(runnable2);
r1.start();
r2.start();
這倆二愣子手下是這樣匯報(bào)工作的
R公司:1號(hào)業(yè)務(wù)員進(jìn)辦公室
R公司:1號(hào)業(yè)務(wù)員開(kāi)始匯報(bào)
R公司:2號(hào)業(yè)務(wù)員進(jìn)辦公室
R公司:2號(hào)業(yè)務(wù)員開(kāi)始匯報(bào)
R公司:1號(hào)業(yè)務(wù)員匯報(bào)完畢
R公司:1號(hào)業(yè)務(wù)員出辦公室
R公司:2號(hào)業(yè)務(wù)員匯報(bào)完畢
R公司:2號(hào)業(yè)務(wù)員出辦公室
小R揉了揉腦袋,嘆氣道:“唉,他們就是這樣匯報(bào)的,每次他們一起講的時(shí)候我都不知該聽(tīng)誰(shuí)的?!眘先生哈哈一笑,道:
“這個(gè)不難解決,下次他們?cè)賮?lái)匯報(bào),進(jìn)來(lái)第一個(gè)人我就把門鎖了,讓下一個(gè)在門外等,等第一個(gè)講完了我再放第二個(gè)進(jìn)來(lái)就行了(當(dāng)一個(gè)線程訪問(wèn)對(duì)象的某個(gè)synchronized同步方法時(shí),其他線程對(duì)對(duì)象中所有其它synchronized同步方法的訪問(wèn)將被阻塞)”
小R聽(tīng)后深以為然,便又安排剛剛那兩個(gè)業(yè)務(wù)員過(guò)來(lái)重新匯報(bào)一次,這次由s先生親自守門
private class ReportTask {
public synchronized void report1(){
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "進(jìn)辦公室");
try{
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "開(kāi)始匯報(bào)");
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "匯報(bào)完畢");
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "出辦公室");
}
public synchronized void report2(){
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "進(jìn)辦公室");
try{
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "開(kāi)始匯報(bào)");
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "匯報(bào)完畢");
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "出辦公室");
}
}
不一會(huì)兒,兩個(gè)業(yè)務(wù)員又來(lái)了,這次的結(jié)果令小R非常滿意
R公司:1號(hào)業(yè)務(wù)員進(jìn)辦公室
R公司:1號(hào)業(yè)務(wù)員開(kāi)始匯報(bào)
R公司:1號(hào)業(yè)務(wù)員匯報(bào)完畢
R公司:1號(hào)業(yè)務(wù)員出辦公室
R公司:2號(hào)業(yè)務(wù)員進(jìn)辦公室
R公司:2號(hào)業(yè)務(wù)員開(kāi)始匯報(bào)
R公司:2號(hào)業(yè)務(wù)員匯報(bào)完畢
R公司:2號(hào)業(yè)務(wù)員出辦公室
看著小R這么開(kāi)心,s先生不禁潑起了冷水:
“你別高興得太早,你窗戶可沒(méi)鎖呢,說(shuō)不定你那幫二愣子手下進(jìn)不了門就從窗戶爬進(jìn)來(lái)了(當(dāng)一個(gè)線程訪問(wèn)對(duì)象的某個(gè)synchronized同步方法時(shí),另一個(gè)線程仍然可以訪問(wèn)該對(duì)象中的非synchronized同步方法)?!?/p>
果然,之后的某次工作匯報(bào)中,這樣的事就發(fā)生了
private class ReportTask {
public synchronized void report1(){
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "進(jìn)辦公室");
try{
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "開(kāi)始匯報(bào)");
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "匯報(bào)完畢");
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "出辦公室");
}
public synchronized void report2(){
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "進(jìn)辦公室");
try{
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "開(kāi)始匯報(bào)");
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "匯報(bào)完畢");
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "出辦公室");
}
public void report3(){
Log.e("R公司","3號(hào)業(yè)務(wù)員" + "進(jìn)辦公室");
try{
Log.e("R公司","3號(hào)業(yè)務(wù)員" + "開(kāi)始匯報(bào)");
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
Log.e("R公司","3號(hào)業(yè)務(wù)員" + "匯報(bào)完畢");
Log.e("R公司","3號(hào)業(yè)務(wù)員" + "出辦公室");
}
}
//線程啟動(dòng)代碼略...
report3()是沒(méi)有修飾的,當(dāng)一個(gè)線程訪問(wèn)對(duì)象的某個(gè)synchronized同步方法時(shí),另一個(gè)線程仍然可以訪問(wèn)該對(duì)象中的非synchronized修飾的方法report3()。
3.3 synchronized同步代碼塊
是日,好友小T前來(lái)拜訪小R,卻看見(jiàn)小R的辦公室門窗緊閉,幾個(gè)業(yè)務(wù)員在門外排著隊(duì)。小T十分疑惑,遂敲門招呼小R讓他開(kāi)門,然而卻沒(méi)有得到任何回應(yīng)。沒(méi)辦法,小T只能跟著業(yè)務(wù)員在辦公室外面等了
private class ReportTask {
public void report1(){
synchronized(this){
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "進(jìn)辦公室");
try{
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "開(kāi)始匯報(bào)");
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "匯報(bào)完畢");
Log.e("R公司","1號(hào)業(yè)務(wù)員" + "出辦公室");
}
}
public void report2(){
synchronized(this){
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "進(jìn)辦公室");
try{
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "開(kāi)始匯報(bào)");
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "匯報(bào)完畢");
Log.e("R公司","2號(hào)業(yè)務(wù)員" + "出辦公室");
}
}
public void report3(){
synchronized(this){
Log.e("R公司","3號(hào)業(yè)務(wù)員" + "進(jìn)辦公室");
try{
Log.e("R公司","3號(hào)業(yè)務(wù)員" + "開(kāi)始匯報(bào)");
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
Log.e("R公司","3號(hào)業(yè)務(wù)員" + "匯報(bào)完畢");
Log.e("R公司","3號(hào)業(yè)務(wù)員" + "出辦公室");
}
}
public void report4(){
synchronized (this){
Log.e("R公司","小T" + "進(jìn)辦公室");
}
}
}
//省略線程啟動(dòng)部分代碼
好不容易等到門開(kāi)了,一個(gè)業(yè)務(wù)員走了出來(lái),小T便一閃身溜了進(jìn)去,門立刻被小R鎖上了?!澳愀缮赌?,差點(diǎn)就夾到我了!”小T抱怨道。小R不好意思笑笑,說(shuō)道:“原來(lái)是小T啊,你坐你坐,待會(huì)再向你解釋,我先放下個(gè)業(yè)務(wù)員進(jìn)來(lái)...”
R公司:1號(hào)業(yè)務(wù)員進(jìn)辦公室
R公司:1號(hào)業(yè)務(wù)員開(kāi)始匯報(bào)
R公司:1號(hào)業(yè)務(wù)員匯報(bào)完畢
R公司:1號(hào)業(yè)務(wù)員出辦公室
R公司:2號(hào)業(yè)務(wù)員進(jìn)辦公室
R公司:2號(hào)業(yè)務(wù)員開(kāi)始匯報(bào)
R公司:2號(hào)業(yè)務(wù)員匯報(bào)完畢
R公司:2號(hào)業(yè)務(wù)員出辦公室
R公司:小T進(jìn)辦公室
R公司:3號(hào)業(yè)務(wù)員進(jìn)辦公室
R公司:3號(hào)業(yè)務(wù)員開(kāi)始匯報(bào)
R公司:3號(hào)業(yè)務(wù)員匯報(bào)完畢
R公司:3號(hào)業(yè)務(wù)員出辦公室
好不容易應(yīng)付完所有業(yè)務(wù)員,小R向小T解釋了來(lái)龍去脈,并拿出了一把鑰匙交給小T
private class ReportTask {
public void report1(){
synchronized(this){
//省略部分代碼...
}
}
public void report2(){
synchronized(this){
//省略部分代碼...
}
}
public void report3(){
synchronized(this){
//省略部分代碼...
}
}
private String window = "window";
public void report4(){
synchronized (window){
Log.e("R公司","小T" + "進(jìn)辦公室");
}
}
}
"s先生自然有應(yīng)對(duì)這種情況的妙計(jì),這把鑰匙可以打開(kāi)窗戶(持有window對(duì)象的內(nèi)置鎖),你以后可以從窗戶直接爬進(jìn)來(lái),不用在門外排隊(duì)(synchronized (obj){}同步代碼塊和用synchronized聲明方法的作用基本一致,都是對(duì)synchronized作用范圍內(nèi)的代碼進(jìn)行加鎖保護(hù),其區(qū)別在于synchronized同步代碼塊使用更加靈活、輕巧,synchronized (obj){}括號(hào)內(nèi)的對(duì)象參數(shù)即為該代碼塊持有鎖的對(duì)象。例如上述例子中,前面三個(gè)report方法中的同步代碼塊持有鎖的對(duì)象為ReportTask的實(shí)例對(duì)象,而report4方法中的同步代碼塊持有鎖的對(duì)象則為window。因?yàn)閷?duì)象都有自己的對(duì)象鎖,只能保護(hù)屬于自己的同步代碼塊或同步方法,所以即使其他線程進(jìn)入前三個(gè)方法的同步代碼塊中并獲得相應(yīng)對(duì)象的鎖,也不會(huì)阻塞進(jìn)入report4方法的線程執(zhí)行其中的同步代碼)。"
拿到鑰匙后,小T再也不用和業(yè)務(wù)員一起在門外排隊(duì)了
3.4 區(qū)分靜態(tài)同步方法和非靜態(tài)同步方法
了解了上述知識(shí)后,我們回過(guò)頭再來(lái)理解同步方法和靜態(tài)同步方法的區(qū)別。從持有鎖的對(duì)象的不同我們可以將synchronized同步代碼的方式分為兩大派系:
- synchronized聲明非靜態(tài)方法、同步代碼塊的synchronized (this){}和synchronized (非this對(duì)象){}這三者持有鎖的對(duì)象為實(shí)例對(duì)象(類的實(shí)例對(duì)象可以有很多個(gè)),線程想要執(zhí)行該synchronized作用范圍內(nèi)的同步代碼,需獲得對(duì)象鎖。
public class SynchronizedTest {
public synchronized void test1(){
//持有鎖的對(duì)象為SynchronizedTest的實(shí)例對(duì)象
}
public void test2(){
synchronized (this){
//持有鎖的對(duì)象為SynchronizedTest的實(shí)例對(duì)象
}
}
private String obj = "obj";
public void test3(){
synchronized (obj){
//持有鎖的對(duì)象為obj
}
}
}
- synchronized聲明靜態(tài)方法以及同步代碼塊的synchronized (類.class){}這兩者持有鎖的對(duì)象為Class對(duì)象(每個(gè)類只有一個(gè)Class對(duì)象,而Class對(duì)象是Java類編譯后生成的.class文件,它包含了與類有關(guān)的信息),線程想要執(zhí)行該synchronized作用范圍內(nèi)的同步代碼,需獲得類鎖
public class SynchronizedTest {
public static synchronized void test4(){
//持有鎖的對(duì)象為SynchronizedTest的Class對(duì)象(SynchronizedTest.class)
}
public void test5(){
synchronized (SynchronizedTest.class){
//持有鎖的對(duì)象為SynchronizedTest的Class對(duì)象(SynchronizedTest.class)
}
}
}
有關(guān)實(shí)例對(duì)象和Class對(duì)象的詳細(xì)知識(shí)大家可以繼續(xù)在網(wǎng)上查找資料進(jìn)行深挖,這里就不贅述了,總之我們要記住的一點(diǎn)是
若synchronized同步方法(代碼塊)持有鎖的對(duì)象不同,則多線程執(zhí)行相應(yīng)的同步代碼時(shí)互不干擾;若相同,則獲得該對(duì)象鎖的線程先執(zhí)行同步代碼,其他訪問(wèn)同步代碼的線程會(huì)被阻塞并等待鎖的釋放