synchronized關(guān)鍵字的使用
- 在日常開(kāi)發(fā)中我們經(jīng)??吹絪ynchronized關(guān)鍵字,常見(jiàn)的幾種應(yīng)用是synchronized(this)、synchronized(class)與synchronized(Object),和synchronize方法,靜態(tài)同步synchronized方法,這幾種方式究竟有什么區(qū)別呢,當(dāng)初學(xué)習(xí)java同步鎖那塊的時(shí)候好像就沒(méi)怎么注意過(guò),現(xiàn)在來(lái)通過(guò)實(shí)例比較下:
-
對(duì)于synchronized(this):
//核心業(yè)務(wù)代碼 public class HotProductService { public void serviceMethodA(){//業(yè)務(wù)A try { synchronized (this) { Log.d("HotProductService","A begin time="+System.currentTimeMillis()); Thread.sleep(2000); Log.d("HotProductService","A end time="+System.currentTimeMillis()); } } catch (InterruptedException e) { e.printStackTrace(); } } public void serviceMethodB(){ synchronized (this) { Log.d("HotProductService","B begin time="+System.currentTimeMillis()); Log.d("HotProductService","B end time="+System.currentTimeMillis()); } } } //線程1 public class ThreadA extends Thread{ private HotProductService objectService; public ThreadA(HotProductService objectService){ super(); this.objectService=objectService; } @Override public void run() { super.run();//調(diào)用業(yè)務(wù)a objectService.serviceMethodA(); } } //線程2 public class ThreadB extends Thread { private HotProductService objectService; public ThreadB(HotProductService objectService){ super(); this.objectService=objectService; } @Override public void run() { super.run();//調(diào)用業(yè)務(wù)b objectService.serviceMethodB(); } } //測(cè)試代碼 private void test1() { HotProductService service=new HotProductService(); ThreadA a=new ThreadA(service); a.start(); ThreadB b=new ThreadB(service); b.start(); }
運(yùn)行結(jié)果:
02-24 10:05:12.135 6434-7477/com.example.refreshdemo D/HotProductService: A begin time=1519437912141
02-24 10:05:14.135 6434-7477/com.example.refreshdemo D/HotProductService: A end time=1519437914142
02-24 10:05:14.135 6434-7478/com.example.refreshdemo D/HotProductService: B begin time=1519437914145
02-24 10:05:14.135 6434-7478/com.example.refreshdemo D/HotProductService: B end time=1519437914146
上面的結(jié)果我們能看到即使A業(yè)務(wù)耗時(shí)較長(zhǎng),B業(yè)務(wù)也并不會(huì)獲得執(zhí)行的機(jī)會(huì),如果我們將核心業(yè)務(wù)代碼中B業(yè)務(wù)或者A業(yè)務(wù)的同步鎖去掉,其他照舊會(huì)是怎么樣
...
比如去掉B業(yè)務(wù)的同步鎖
public void serviceMethodB(){
//synchronized (this)
{
Log.d("HotProductService","B begin time="+System.currentTimeMillis());
Log.d("HotProductService","B end time="+System.currentTimeMillis());
}
}
...
運(yùn)行結(jié)果:
02-24 02:27:19.248 3562-3629/com.example.refreshdemo D/HotProductService: A begin time=1519439239248
02-24 02:27:19.248 3562-3630/com.example.refreshdemo D/HotProductService: B begin time=1519439239248
02-24 02:27:19.248 3562-3630/com.example.refreshdemo D/HotProductService: B end time=1519439239248
02-24 02:27:21.248 3562-3629/com.example.refreshdemo D/HotProductService: A end time=1519439241248
結(jié)論:synchronized (this)使用的對(duì)象監(jiān)視器是一個(gè),即是該對(duì)象自身,當(dāng)一個(gè)線程訪問(wèn)HotProductService的一個(gè)synchronized (this)同步代碼塊時(shí),其它線程對(duì)同一個(gè)HotProductService中其它的synchronized (this)同步代碼塊的訪問(wèn)將是堵塞,實(shí)現(xiàn)了代碼順序的同步執(zhí)行。
-
對(duì)于synchronized修飾的方法:
上面的結(jié)論對(duì)于synchronized修飾的方法是否同樣有效呢,通過(guò)實(shí)例看下://核心業(yè)務(wù)代碼 public class HotProductService { //業(yè)務(wù)A public synchronized void objectMethodA(){ Log.d("HotProductService","run----objectMethodA2"); } //業(yè)務(wù)B public void objectMethodB(){ synchronized (this) { try { for (int i = 1; i <= 10; i++) { Log.d("HotProductService","synchronized thread name:"+Thread.currentThread().getName()+"-->i="+i); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } } } //A線程 public class ThreadA2 extends Thread{ private HotProductService objectService; public ThreadA2(HotProductService objectService){ super(); this.objectService=objectService; } @Override public void run() { super.run(); objectService.objectMethodA(); } } //B線程 public class ThreadB2 extends Thread { private HotProductService objectService; public ThreadB2(HotProductService objectService){ super(); this.objectService=objectService; } @Override public void run() { super.run(); objectService.objectMethodB(); } } private void test2() { HotProductService service=new HotProductService(); ThreadA2 a=new ThreadA2(service); a.start(); ThreadB2 b=new ThreadB2(service); b.start(); }
運(yùn)行結(jié)果:
02-24 02:48:32.212 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=1
02-24 02:48:33.213 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=2
02-24 02:48:34.214 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=3
02-24 02:48:35.215 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=4
02-24 02:48:36.216 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=5
02-24 02:48:37.217 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=6
02-24 02:48:38.218 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=7
02-24 02:48:39.219 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=8
02-24 02:48:40.220 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=9
02-24 02:48:41.221 3562-3765/com.example.refreshdemo D/HotProductService: synchronized thread name:Thread-166-->i=10
02-24 02:48:42.223 3562-3764/com.example.refreshdemo D/HotProductService: run----objectMethodA2
同樣驗(yàn)證了只能同時(shí)被一個(gè)線程所訪問(wèn)synchronized代碼塊。其他線程遇到synchronized代碼塊將會(huì)堵塞。
-
那么synchronized(Object)呢
//核心業(yè)務(wù)代碼 public class HotProductService { private String uname; private String pwd; String lock=new String(); public void setUserNamePassWord(String userName,String passWord){ try { synchronized (lock) { Log.d("HotProductService","thread name=" + Thread.currentThread().getName() + " 進(jìn)入代碼快:" + System.currentTimeMillis()); uname=userName; Thread.sleep(3000); pwd=passWord; Log.d("HotProductService","thread name="+Thread.currentThread().getName() +" 進(jìn)入代碼快:"+System.currentTimeMillis()+"入?yún)name:"+uname+"入?yún)wd:"+pwd); } } catch (InterruptedException e) { e.printStackTrace(); } } } //A線程 public class ThreadA3 extends Thread{ private HotProductService objectService; public ThreadA3(HotProductService objectService){ super(); this.objectService=objectService; } @Override public void run() { super.run(); objectService.setUserNamePassWord("a","aa"); } } //B線程 public class ThreadB3 extends Thread { private HotProductService objectService; public ThreadB3(HotProductService objectService){ super(); this.objectService=objectService; } @Override public void run() { super.run(); objectService.setUserNamePassWord("b","bb"); } } HotProductService service=new HotProductService(); ThreadA2 a=new ThreadA2(service); a.start(); ThreadB2 b=new ThreadB2(service); b.start();
運(yùn)行結(jié)果:
02-24 02:57:41.380 3975-4016/? D/HotProductService: thread name=A 進(jìn)入代碼快:1519441061380
02-24 02:57:44.382 3975-4016/com.example.refreshdemo D/HotProductService: thread name=A 進(jìn)入代碼快:1519441064382入?yún)name:a入?yún)wd:aa
02-24 02:57:44.382 3975-4017/com.example.refreshdemo D/HotProductService: thread name=B 進(jìn)入代碼快:1519441064382
02-24 02:57:47.383 3975-4017/com.example.refreshdemo D/HotProductService: thread name=B 進(jìn)入代碼快:1519441067383入?yún)name:b入?yún)wd:bb
如果我們將
//核心業(yè)務(wù)代碼
public class HotProductService {
private String uname;
private String pwd;
//String lock=new String();移入方法會(huì)得到什么樣的結(jié)果呢
public void setUserNamePassWord(String userName,String passWord){
try {
String lock=new String();
synchronized (lock) {
Log.d("HotProductService","thread name=" + Thread.currentThread().getName()
+ " 進(jìn)入代碼快:" + System.currentTimeMillis());
uname=userName;
Thread.sleep(3000);
pwd=passWord;
Log.d("HotProductService","thread name="+Thread.currentThread().getName()
+" 進(jìn)入代碼快:"+System.currentTimeMillis()+"入?yún)name:"+uname+"入?yún)wd:"+pwd);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
其他代碼照舊得到
運(yùn)行結(jié)果:
02-24 03:04:16.757 4148-4187/? D/HotProductService: thread name=A 進(jìn)入代碼快:1519441456757
02-24 03:04:16.758 4148-4188/? D/HotProductService: thread name=B 進(jìn)入代碼快:1519441456758
02-24 03:04:19.758 4148-4187/com.example.refreshdemo D/HotProductService: thread name=A 進(jìn)入代碼快:1519441459758入?yún)name:b入?yún)wd:aa
02-24 03:04:19.759 4148-4188/com.example.refreshdemo D/HotProductService: thread name=B 進(jìn)入代碼快:1519441459759入?yún)name:b入?yún)wd:bb
是不是很奇怪出錯(cuò)了?為什么呢 移入方法內(nèi)部就不對(duì)了,比較前后改變,發(fā)現(xiàn)修改后每次調(diào)用方法時(shí)(哪個(gè)線程調(diào)用方法時(shí))都會(huì)重新new一個(gè)對(duì)象作為對(duì)象鎖,但是修改前不管哪次進(jìn)入方法時(shí)(哪個(gè)線程調(diào)用方法時(shí))用的都是同一個(gè)對(duì)象,所以我們得到結(jié)論:
使用自定義任意對(duì)象進(jìn)行同步鎖 不同線程必須為同一對(duì)象,否則仍舊是異步運(yùn)行的
- synchronized(.class)與靜態(tài)同步synchronized方法
可以直接給出的結(jié)論是這兩種方式的同步是一樣的,使用的同步鎖都是對(duì)應(yīng)的類(lèi)作為對(duì)象鎖,在jvm中類(lèi)是唯一的,那也就是說(shuō)對(duì)任何對(duì)象都是同步的,因?yàn)榫哂形ㄒ坏膶?duì)象鎖。下面來(lái)驗(yàn)證下:
//核心業(yè)務(wù)代碼
public class HotProductService {
//業(yè)務(wù)A
public void methodA(){
try {
synchronized (HotProductService.class){
Log.d("HotProductService","static methodA begin Name:" + Thread.currentThread().getName() + " times:" + System.currentTimeMillis());
Thread.sleep(2000);
Log.d("HotProductService","static methodA end Name:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//業(yè)務(wù)B
public void methodB(){
synchronized (HotProductService.class){
Log.d("HotProductService","static methodB begin Name:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
Log.d("HotProductService","static methodB end Name:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
}
}
}
//A線程
public class ThreadA5 extends Thread{
private HotProductService mHotProductService;
public ThreadA5(HotProductService hotProductService){
mHotProductService = hotProductService;
}
@Override
public void run() {
super.run();
mHotProductService.methodA();
}
}
//B線程
public class ThreadB5 extends Thread {
private HotProductService mHotProductService;
public ThreadB5(HotProductService hotProductService){
mHotProductService = hotProductService;
}
@Override
public void run() {
super.run();
mHotProductService.methodB();
}
}
private void test5() {
HotProductService service= new HotProductService();
ThreadA5 a=new ThreadA5(service);
a.start();
ThreadB5 b=new ThreadB5(service);
b.start();
}
運(yùn)行結(jié)果:
02-24 03:24:11.250 4148-4282/com.example.refreshdemo D/HotProductService: static methodA begin Name:Thread-174 times:1519442651250
02-24 03:24:13.252 4148-4282/com.example.refreshdemo D/HotProductService: static methodA end Name:Thread-174 times:1519442653252
02-24 03:24:13.252 4148-4283/com.example.refreshdemo D/HotProductService: static methodB begin Name:Thread-175 times:1519442653252
02-24 03:24:13.252 4148-4283/com.example.refreshdemo D/HotProductService: static methodB end Name:Thread-175 times:1519442653252
使用.class作為對(duì)象鎖保證了不能線程的同步。
引用網(wǎng)上常見(jiàn)的說(shuō)法就是:
synchronize修飾的方法和 synchronize(this) 都是鎖住自己本身的對(duì)象 而synchronize(class) synchronize(object) 都是鎖別的對(duì)象