現在的位置: 首頁 > 演算法 > 正文

Java synchronized 對象鎖和類鎖有什麼區別

2020年02月25日 演算法 ⁄ 共 3518字 ⁄ 字型大小 評論關閉

  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");

  }

  三個線程的代碼如下:

  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中方法)。

  我們知道對象鎖要想保持同步執行,那麼鎖住的必須是同一個對象。下面就修改下上面的來證明:

  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。也就是說,類鎖對所有的該類對象都能起作用。

  總結:

  1. 如果多線程同時訪問同一類的 類鎖(synchronized 修飾的靜態方法)以及對象鎖(synchronized 修飾的非靜態方法)這兩個方法執行是非同步的,原因:類鎖和對象鎖是2中不同的鎖。

  2. 類鎖對該類的所有對象都能起作用,而對象鎖不能。

抱歉!評論已關閉.