Java synchronized 类锁和对象锁的区别

synchronized 加到 static 方法前面是给class 加锁,即类锁;而synchronized 加到非静态方法前面是给对象上锁。这两者的区别我用代码来演示下:

1.类锁和对象锁是两把不同的锁,多线程执行两个不同锁的方法时是异步的

加锁的类(下面几个此类不变)

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函数如下

public static void main(String[] args) {
         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
name = C, begain
name = C, end
name = A, end
name = B, begain
name = B, end

doLongTimeTaskA()和 doLongTimeTaskB()互斥,与doLongTimeTaskC()不互斥,类锁和对象锁是两类不同的锁

2,对象锁对同一个实列对象起作用,类锁对该类的所有实列对象起作用

加锁类不变,用上面的

多线程更改如下

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函数如下

public static void main(String[] args) {
    
      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
name = B, begain
name = A, end
name = B, end

对象锁锁的对象不一样,分别是mTaska , mTaskb,所以线程A和线程B调用 doLongTimeTaskC 是异步执行的。

然后我们main函数不变,依旧是对两个实列而言 ,更改多线程的class走类锁,执行doLongTimeTaskA()或者doLongTimeTaskB()

更改后的多线程类如下

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();
    }
}

 

结果如下

name = A, begain
name = A, end
name = B, begain
name = B, end

可以看出 在线程A执行完doLongTimeTaskA方法后,线程B才会获得该类锁接着去执行doLongTimeTaskA。也就是说,类锁对所有的该类对象都能起作用。

结论:

1. 如果多线程同时访问同一类的 类锁(synchronized 修饰的静态方法)以及对象锁(synchronized 修饰的非静态方法)这两个方法执行是异步的,原因:类锁和对象锁是2种不同的锁。 
2. 类锁对该类的所有对象都能起作用,而对象锁只对同一个实例对象起作用。

猜你喜欢

转载自blog.csdn.net/weixin_42446078/article/details/81236042