點擊上方Java學習指南關注公衆號
java
天天閱讀Java乾貨文章web
synchronized 加到 static 方法前面是給class 加鎖,即類鎖;而synchronized 加到非靜態方法前面是給對象上鎖。面試
這二者的區別我用代碼來演示下微信
對象鎖和類鎖是不一樣的鎖,因此多個線程同時執行這2個不一樣鎖的方法時,是異步的。
在Task2 中定義三個方法 doLongTimeTaskA和doLongTimeTaskB是類鎖,而doLongTimeTaskC是對象鎖。多線程
public class Task2 {
public synchronized static void doLongTimeTaskA() {
System.out.println("name = " + Thread.currentThread().getName() + ", begain");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
public synchronized static void doLongTimeTaskB() {
System.out.println("name = " + Thread.currentThread().getName() + ", begain");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
public synchronized void doLongTimeTaskC() {
System.out.println("name = " + Thread.currentThread().getName() + ", begain");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
三個線程的代碼以下:app
class ThreadA extends Thread{
private Task2 mTask2;
public ThreadA(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskA();
}
}
class ThreadB extends Thread{
private Task2 mTask2;
public ThreadB(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskB();
}
}
class ThreadC extends Thread{
private Task2 mTask2;
public ThreadC(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskC();
}
}
main函數中執行代碼以下:異步
Task2 mTask2 = new Task2();
ThreadA ta = new ThreadA(mTask2);
ThreadB tb = new ThreadB(mTask2);
ThreadC tc = new ThreadC(mTask2);
ta.setName("A");
tb.setName("B");
tc.setName("C");
ta.start();
tb.start();
tc.start();
執行的結果以下:編輯器
name = A, begain, time = 1487311199783
name = C, begain, time = 1487311199783
name = C, end, time = 1487311200784
name = A, end, time = 1487311200784
name = B, begain, time = 1487311200784
name = B, end, time = 1487311201784
能夠看出因爲 doLongTimeTaskA和doLongTimeTaskB都是類鎖,即同一個鎖,因此 A和B是按順序執行,即同步的。而C是對象鎖,和A/B不是同一種鎖,因此C和A、B是 異步執行的。(A、B、C代指上面的3中方法)。函數
更多面試題,歡迎關注公衆號 Java面試題精選學習
咱們知道對象鎖要想保持同步執行,那麼鎖住的必須是同一個對象。下面就修改下上面的來證實:
Task2.java不變,修改ThreadA 和 ThreadB 以下:
class ThreadA extends Thread{
private Task2 mTask2;
public ThreadA(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskC();
}
}
class ThreadB extends Thread{
private Task2 mTask2;
public ThreadB(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskC();
}
}
main方法以下:
Task2 mTaska = new Task2();
Task2 mTaskb = new Task2();
ThreadA ta = new ThreadA(mTaska );
ThreadB tb = new ThreadB(mTaskb );
ta.setName("A");
tb.setName("B");
ta.start();
tb.start();
結果以下:
name = A, begain, time = 1487311905775
name = B, begain, time = 1487311905775
name = B, end, time = 1487311906775
name = A, end, time = 1487311906775
從結果看來,對象鎖鎖的對象不同,分別是mTaska , mTaskb,因此線程A和線程B調用 doLongTimeTaskC 是異步執行的。
可是,類鎖能夠對類的全部對象的實例起做用。只需修改ThradA 和 ThreadB,main 方法不作改變,修改以下:
class ThreadA extends Thread{
private Task2 mTask2;
public ThreadA(Task2 tk){
mTask2 = tk;
}
public void run() {
//mTask2.doLongTimeTaskC();
mTask2.doLongTimeTaskA();
}
}
class ThreadB extends Thread{
private Task2 mTask2;
public ThreadB(Task2 tk){
mTask2 = tk;
}
public void run() {
//mTask2.doLongTimeTaskC();
mTask2.doLongTimeTaskA();
}
}
結果以下:
name = A, begain, time = 1487312239674
name = A, end, time = 1487312240674
name = B, begain, time = 1487312240674
name = B, end, time = 1487312241674
能夠看出 在線程A執行完doLongTimeTaskA方法後,線程B纔會得到該類鎖接着去執行doLongTimeTaskA。也就是說,類鎖對全部的該類對象都能起做用。
Java學習指南:一個只分享Java乾貨的公衆號。
總結:
-
若是多線程同時訪問同一類的 類鎖(synchronized 修飾的靜態方法)以及對象鎖(synchronized 修飾的非靜態方法)這兩個方法執行是異步的,緣由:類鎖和對象鎖是兩種不一樣的鎖。 -
類鎖對該類的全部對象都能起做用,而對象鎖不能。
做者:小豬快跑22
blog.csdn.net/zhujiangtaotaise/article/details/55509939
若是文章對您有幫助,請您分享、點贊、在看,一波三連支持一下做者,很是感謝!
本文分享自微信公衆號 - Java學習指南(gh_85b94beaede2)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。