【68期】面試官:對(duì)并發(fā)熟悉嗎?說(shuō)說(shuō)Synchronized及實(shí)現(xiàn)原理
閱讀本文大概需要 7 分鐘。
來(lái)自:www.cnblogs.com/paddix/p/5367116.html
一、Synchronized的基本使用
確保線程互斥的訪問(wèn)同步代碼
保證共享變量的修改能夠及時(shí)可見(jiàn)
有效解決重排序問(wèn)題。
修飾普通方法
修飾靜態(tài)方法
修飾代碼塊
1、沒(méi)有同步的情況:
package?com.paddx.test.concurrent;
public?class?SynchronizedTest?{
????public?void?method1(){
????????System.out.println("Method?1?start");
????????try?{
????????????System.out.println("Method?1?execute");
????????????Thread.sleep(3000);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????System.out.println("Method?1?end");
????}
????public?void?method2(){
????????System.out.println("Method?2?start");
????????try?{
????????????System.out.println("Method?2?execute");
????????????Thread.sleep(1000);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????System.out.println("Method?2?end");
????}
????public?static?void?main(String[]?args)?{
????????final?SynchronizedTest?test?=?new?SynchronizedTest();
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????test.method1();
????????????}
????????}).start();
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????test.method2();
????????????}
????????}).start();
????}
}
Method 1 start
Method 1 execute
Method 2 start
Method 2 execute
Method 2 end
Method 1 end
2、對(duì)普通方法同步:
package?com.paddx.test.concurrent;
public?class?SynchronizedTest?{
????public?synchronized?void?method1(){
????????System.out.println("Method?1?start");
????????try?{
????????????System.out.println("Method?1?execute");
????????????Thread.sleep(3000);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????System.out.println("Method?1?end");
????}
????public?synchronized?void?method2(){
????????System.out.println("Method?2?start");
????????try?{
????????????System.out.println("Method?2?execute");
????????????Thread.sleep(1000);
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????System.out.println("Method?2?end");
????}
????public?static?void?main(String[]?args)?{
????????final?SynchronizedTest?test?=?new?SynchronizedTest();
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????test.method1();
????????????}
????????}).start();
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????test.method2();
????????????}
????????}).start();
????}
}
Method 1 start
Method 1 execute
Method 1 end
Method 2 start
Method 2 execute
Method 2 end
3、靜態(tài)方法(類)同步
package?com.paddx.test.concurrent;
?public?class?SynchronizedTest?{
?????public?static?synchronized?void?method1(){
?????????System.out.println("Method?1?start");
?????????try?{
?????????????System.out.println("Method?1?execute");
?????????????Thread.sleep(3000);
?????????}?catch?(InterruptedException?e)?{
?????????????e.printStackTrace();
?????????}
?????????System.out.println("Method?1?end");
?????}
?????public?static?synchronized?void?method2(){
?????????System.out.println("Method?2?start");
?????????try?{
?????????????System.out.println("Method?2?execute");
?????????????Thread.sleep(1000);
?????????}?catch?(InterruptedException?e)?{
?????????????e.printStackTrace();
?????????}
?????????System.out.println("Method?2?end");
?????}
?????public?static?void?main(String[]?args)?{
?????????final?SynchronizedTest?test?=?new?SynchronizedTest();
?????????final?SynchronizedTest?test2?=?new?SynchronizedTest();
?????????new?Thread(new?Runnable()?{
?????????????@Override
?????????????public?void?run()?{
?????????????????test.method1();
?????????????}
?????????}).start();
?????????new?Thread(new?Runnable()?{
?????????????@Override
?????????????public?void?run()?{
?????????????????test2.method2();
?????????????}
?????????}).start();
?????}
?}
Method 1 start
Method 1 execute
Method 1 end
Method 2 start
Method 2 execute
Method 2 end
4、代碼塊同步
package?com.paddx.test.concurrent;
public?class?SynchronizedTest?{
????public?void?method1(){
????????System.out.println("Method?1?start");
????????try?{
????????????synchronized?(this)?{
????????????????System.out.println("Method?1?execute");
????????????????Thread.sleep(3000);
????????????}
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????System.out.println("Method?1?end");
????}
????public?void?method2(){
????????System.out.println("Method?2?start");
????????try?{
????????????synchronized?(this)?{
????????????????System.out.println("Method?2?execute");
????????????????Thread.sleep(1000);
????????????}
????????}?catch?(InterruptedException?e)?{
????????????e.printStackTrace();
????????}
????????System.out.println("Method?2?end");
????}
????public?static?void?main(String[]?args)?{
????????final?SynchronizedTest?test?=?new?SynchronizedTest();
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????test.method1();
????????????}
????????}).start();
????????new?Thread(new?Runnable()?{
????????????@Override
????????????public?void?run()?{
????????????????test.method2();
????????????}
????????}).start();
????}
}
Method 1 start
Method 1 execute
Method 2 start
Method 1 end
Method 2 execute
Method 2 end
二、Synchronized 原理
package?com.paddx.test.concurrent;
public?class?SynchronizedDemo?{
????public?void?method()?{
????????synchronized?(this)?{
????????????System.out.println("Method?1?start");
????????}
????}
}

Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread that executes monitorenter attempts to gain ownership of the monitor associated with objectref, as follows:
If the entry count of the monitor associated with objectref is zero, the thread enters the monitor and sets its entry count to one. The thread is then the owner of the monitor.
If the thread already owns the monitor associated with objectref, it reenters the monitor, incrementing its entry count.
If another thread already owns the monitor associated with objectref, the thread blocks until the monitor's entry count is zero, then tries again to gain ownership.
如果monitor的進(jìn)入數(shù)為0,則該線程進(jìn)入monitor,然后將進(jìn)入數(shù)設(shè)置為1,該線程即為monitor的所有者。
如果線程已經(jīng)占有該monitor,只是重新進(jìn)入,則進(jìn)入monitor的進(jìn)入數(shù)加1.
如果其他線程已經(jīng)占用了monitor,則該線程進(jìn)入阻塞狀態(tài),直到monitor的進(jìn)入數(shù)為0,再重新嘗試獲取monitor的所有權(quán)。
The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.
The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner. Other threads that are blocking to enter the monitor are allowed to attempt to do so.
package?com.paddx.test.concurrent;
public?class?SynchronizedMethod?{
????public?synchronized?void?method()?{
????????System.out.println("Hello?World!");
????}
}

三、運(yùn)行結(jié)果解釋
1、代碼段2結(jié)果:
2、代碼段3結(jié)果:
3、代碼段4結(jié)果:
四 總結(jié)
推薦閱讀:
【67期】談?wù)凜oncurrentHashMap是如何保證線程安全的?
【66期】Java容器面試題:談?wù)勀銓?duì) HashMap 的理解
微信掃描二維碼,關(guān)注我的公眾號(hào)
朕已閱?

