文章目錄
- 前言
- 一、Synchronized修飾非靜态方法
- 二、Synchronized修飾靜态方法
- 三、類鎖和對象鎖的通路是不沖突的
- 四、總結
前言
直接說結論:
1.Synchronized修飾非靜态方法,實際上是對調用該方法的對象加鎖,俗稱“對象鎖”。
2.Synchronized修飾靜态方法,實際上是對該類對象加鎖,俗稱“類鎖”。
3.對于類鎖synchronized static,是通過該類直接調用加類鎖的方法,而對象鎖是建立對象調用加對象鎖的方法,兩者通路是不沖突的,對于同一類型鎖鎖住的方法,同一對象是無法同時通路的.
一、Synchronized修飾非靜态方法
Synchronized修飾非靜态方法,實際上是對調用該方法的對象加鎖,俗稱“對象鎖”。
如果采用形象的比喻就是,對于這個對象可能有很多方法(房間),有一些加了鎖(鎖門的房間),而這些房間共用一把鑰匙,導緻當一個被鎖方法被通路時,無法通路其他帶鎖的方法。
但是需要注意:一個對象可以拿一把鑰匙,多個對象可以插隊執行。
考慮下圖代碼,想一下會輸出什麼。
public class TestSyn {
public static void main(String[] args) {
Number number = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
}
}).start();
}
}
class Number{
public synchronized void getOne(){
try {
Thread.sleep(2000);
System.out.println("one");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void getTwo(){
System.out.println("two");
}
}
答案是輸出one two
因為getOne()雖然要停止2秒,但上了對象鎖,getTwo()不能超車(通路),要等getOne()被調用完,把鑰匙換回來,才能繼續執行
二、Synchronized修飾靜态方法
Synchronized修飾靜态方法,實際上是對該類對象加鎖,俗稱“類鎖”。
類對象隻有一個,隻在郊外有這一棟别墅,裡面的靜态方法也被一把鎖管着。因為一個類對象隻能拿一把鎖。
将兩個方法都設為static,猜猜會輸出什麼
package JUC_test;
public class TestSyn {
public static void main(String[] args) {
Number number = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
}
}).start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(2000);
System.out.println("one");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void getTwo(){
System.out.println("two");
}
}
輸出one two
也可以不new對象直接類對象調用
package JUC_test;
public class TestSyn {
public static void main(String[] args) {
Number number = new Number();
new Thread(new Runnable() {
@Override
public void run() {
// number.getOne();
Number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// number.getTwo();
Number.getTwo();
}
}).start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(2000);
System.out.println("one");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void getTwo(){
System.out.println("two");
}
}
答案是 one two
顯然,這次我們直接插隊進别墅大門失敗了,很好地解釋了類鎖
三、類鎖和對象鎖的通路是不沖突的
現在我們設定為one靜态,two非靜态,猜猜會發生什麼
package JUC_test;
public class TestSyn {
public static void main(String[] args) {
Number number = new Number();
new Thread(new Runnable() {
@Override
public void run() {
// number.getOne();
Number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
number.getTwo();
// Number.getTwo();
}
}).start();
}
}
class Number{
public static synchronized void getOne(){
try {
Thread.sleep(2000);
System.out.println("one");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void getTwo(){
System.out.println("two");
}
}
答案是 two one
你開别墅大門,關我别墅内的狗窩什麼事?
package JUC_test;
public class TestSyn {
public static void main(String[] args) {
Number number = new Number();
new Thread(new Runnable() {
@Override
public void run() {
number.getOne();
// Number.getOne();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// number.getTwo();
Number.getTwo();
}
}).start();
}
}
class Number{
public synchronized void getOne(){
try {
Thread.sleep(2000);
System.out.println("one");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void getTwo(){
System.out.println("two");
}
}
答案是 two one
同理,你開狗窩大門,關我别墅什麼事?
四、總結
對于synchronized修飾方法的調用
我們考慮了
非靜态 非靜态
靜态 靜态
靜态 非靜态
非靜态 靜态
四種情況,
可以留下思考,如果這些換成兩個對象去調用呢?
答案會是什麼呢?
two one
one two(有兩個執行個體對象,但隻有一個類對象)
two one
two one