Java基础问题系列-同步之Synchronized关键字

一个问题,有简单的类如下,有一个静态synchronized方法,两个非静态synchronized方法,这个类的两个对象(实例):A,B,那么以下几种情况中,那种组合的方法执行会发生互斥(锁竞争)?

1、SyncTest.method1,A.method1;2、A.method2, B.method2;3、SyncTest.method1,A.method2;4、A.method2,A.method3

类示例代码如下:

public class SyncTest {

    public synchronized static void method1(String name){
        System.out.println(name+" is running method1 start");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException e){

        }
        System.out.println(name+" is running method1 end");
    }

    public synchronized void method2(String name){
        System.out.println(name+" is running method2 start");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException e){

        }
        System.out.println(name+" is running method2 end");
    }

    public synchronized void method3(String name){
        System.out.println(name+" is running method3 start");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException e){

        }
        System.out.println(name+" is running method3 end");
    }

}

先说结果:

发生互斥情况的组合为: 1、SyncTest.method1,A.method1;4、A.method2,A.method3

不互斥的情况为:2、A.method2, B.method2;3、SyncTest.method1,A.method2;

其实也并不复杂,了解synchronize的作用域这个问题就很清晰了、

1、synchronized修饰静态方法时,锁是类锁(.class)。这个范围就比对象锁大。这里就算是不同对象,但是只要是该类的对象,就使用的是同一把锁。多个线程调用该类的同步的静态方法时,都会阻塞。所以 1 成立

2、synchronized修饰普通方法时,锁是对象锁(this)。

当该类中有多个普通方法被synchronized修饰(同步),那么这些方法的锁都是这个类的一个对象this。多个线程访问这些方法时,如果这些线程调用方法时使用的是同一个该类的对象,虽然他们访问不同方法,但是他们使用同一个对象来调用,那么这些方法的锁就是一样的,就是这个对象,那么会造成阻塞。如果多个线程通过不同的对象来调用方法(一般都是通过同一个对象访问),那么他们的锁就是不一样的,不会造成阻塞。

所以4 是使用一个对象中的两个synchronized方法,执行时都锁当前对象,导致出现竞争。

用于验证的执行代码示例如下:

package com.java.learn.mine.basic.lock.synchronizetest;


public class SyncTest {

    public synchronized static void method1(String name){
        System.out.println(name+" is running method1 start");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException e){

        }
        System.out.println(name+" is running method1 end");
    }

    public synchronized void method2(String name){
        System.out.println(name+" is running method2 start");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException e){

        }
        System.out.println(name+" is running method2 end");
    }

    public synchronized void method3(String name){
        System.out.println(name+" is running method3 start");
        try{
            Thread.sleep(2000);
        }catch (InterruptedException e){

        }
        System.out.println(name+" is running method3 end");
    }

    public static void main(String[] args){
        SyncTest syncTest = new SyncTest();
//        SyncTest syncTestA2 = new SyncTest();


        Thread threadA = new ThreadA(syncTest);
        Thread threadB = new ThreadB(syncTest);

        threadA.start();
        threadB.start();
    }
}

class ThreadA extends Thread{
    private SyncTest syncTest;

    public ThreadA(SyncTest syncTest){
        this.syncTest = syncTest;
    }

    @Override
    public void run(){
//        SyncTest.method1("ThreadA");

//        SyncTest syncTest = new SyncTest();
//        syncTest.method2("ThreadA");

//        syncTest.method2(ThreadA.class.getName());

        SyncTest.method1(ThreadA.class.getName());
    }
}

class ThreadB extends Thread{
    private SyncTest syncTest;

    public ThreadB(SyncTest syncTest){
        this.syncTest = syncTest;
    }

    @Override
    public void run(){
//        SyncTest syncTest = new SyncTest();
//        SyncTest.method1("ThreadB");
//        syncTest.method1("ThreadB");

//        syncTest.method2(ThreadB.class.getName());
        syncTest.method3(ThreadB.class.getName());
    }
}

执行后,可以通过打印信息中的start、end来判定两个线程是否同时开始执行方法;进而确定是否发生了锁竞争

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章