现在的位置: 首页 > 算法 > 正文

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. 类锁对该类的所有对象都能起作用,而对象锁不能。

抱歉!评论已关闭.