자바 synchronized(this)와 synchronized(object)의 차이

25576 단어 Javasynchronized
머리말
최근 글 라 이 드 4.11 의 소스 코드 를 보다 가 본의 아니 게 다음 코드 를 봤 다.왜 이 걸 직접 쓰 지 않 으 면 되 는 지 궁금 하 네요.굳이 Object 대상 을 쓰 겠 다 고?뒤에 한 차례 의 탐 구 를 통 해 차이 점 을 발견 하 였 다.
 public static class SynchronizedPool<T> extends SimplePool<T> {
 
        private final Object mLock = new Object();
        
        public SynchronizedPool(int maxPoolSize) {
            super(maxPoolSize);
        }
        @Override
        public T acquire() {
            synchronized (mLock) {
                return super.acquire();
            }
        }
        @Override
        public boolean release(@NonNull T element) {
            synchronized (mLock) {
                return super.release(element);
            }
        }
    }

1.동기 화 작용 이 같다.다 중 스 레 드 가 같은 인 스 턴 스 방법 에 대한 동기 화 를 실현 할 수 있 습 니 다.
둘째,자물쇠 대상 이 다르다.synchronized(this),잠 긴 대상 은 this,클래스 의 인 스 턴 스 입 니 다.synchronized(object),잠 긴 대상 은 object 입 니 다.
 class Test{
    private final Object object = new Object();
    public void print(){
        synchronized (object){
            System.out.println("xxxx");
        }
    }
}
 class Test{
    public void print(){
        synchronized (this){
            System.out.println("xxxx");
        }
    }
}

3.그런데 왜 synchronized(object)라 는 방식 으로 object 대상 을 하나 더 만 들 었 습 니까?다음 코드 부터 봅 시다.

class STest{
 
    public void print(){
        synchronized (this){
            System.out.println("xxxx");
        }
    }
}

public class SynchronizeMain {

    public static void main(String[] args) throws InterruptedException {

        STest sTest = new STest();

        // Thread 1
        Thread t1 = new Thread(() -> {
            sTest.print();
        });

        // Thread 2
       Thread t2 = new Thread(() -> {

           try {
               synchronized (sTest){
                   while (true);
               }
           } catch (Exception e) {
               System.out.println("Exception="+e.getMessage());
           }

        });

       t2.start();
       t1.start();
    }
}


출력 결 과 는 아무것도 없습니다!이 유 는 synchronized(this)의 잠 금 대상 이 this 이기 때 문 입 니 다.만약 에 이런 방식 을 사용 하면 잠 금 대상(인 스 턴 스)을 다른 사람 이 가 져 오 면 다른 사람 이 스 레 드 2 처럼 스 레 드 를 열 면 당신 의 Thread 1,이 정상 적 인 작업 스 레 드 는 영원히 실행 되 지 못 하고 잠 금 을 만 듭 니 다.다른 예 를 다시 봅 시다.

 class STest{

    private final Object object = new Object();
    public void print(){
        synchronized (object){
            System.out.println("xxxx");
        }
    }
}

public class SynchronizeMain {

    public static void main(String[] args) throws InterruptedException {

        STest sTest = new STest();

        // Thread 1
        Thread t1 = new Thread(() -> {
            sTest.print();
        });

        // Thread 2
       Thread t2 = new Thread(() -> {

           try {
               synchronized (sTest){
                   while (true);
               }
           } catch (Exception e) {
               System.out.println("Exception="+e.getMessage());
           }

        });

       t2.start();
       Thread.sleep(1000);
       t1.start();
    }
}


출력 결 과 는 xxxx!synchronized(object),잠 긴 대상 이 object 이기 때문이다.그래서 sTest 의 인 스 턴 스 를 받 았 고 Thread 1 의 정상 적 인 실행 에 영향 을 주지 않 습 니 다.
4.만약 에 제 가 반 사 를 통 해 object 변 수 를 가 져 와 Thread 2 에 들 어가 면 어떻게 될까요?
그렇다면 Thread 1,이 정상 적 인 작업 스 레 드 는 영원히 실행 되 지 않 고 잠 금 을 만 들 수 있 습 니 다.Talk is cheap, Show me code:

 class STest{

    private final Object object = new Object();
    public void print(){
        synchronized (object){
            System.out.println("xxxx");
        }
    }
}

public class SynchronizeMain {

    public static void main(String[] args) throws InterruptedException {

        STest sTest = new STest();

        // Thread 1
        Thread t1 = new Thread(() -> {
            sTest.print();
        });

        // Thread 2
       Thread t2 = new Thread(() -> {

           try {
               synchronized (getPrivateField(sTest,"object")){
                   while (true);
               }
           } catch (Exception e) {
               System.out.println("Exception="+e.getMessage());
           }

        });

       t2.start();
       Thread.sleep(1000);
       t1.start();
    }

    public static Object getPrivateField(Object instance, String filedName) throws NoSuchFieldException, IllegalAccessException {
        Field field = instance.getClass().getDeclaredField(filedName);
        field.setAccessible(true);
        return field.get(instance);
    }

}


출력 결 과 는 아무것도 없습니다!synchronized(object)의 잠 금 대상 은 object 이 고 object 는 Thread 2 에 의 해 점용 되 었 기 때 문 입 니 다.
총결산
잠 금 대상 을 선택 할 때 잠 금 대상 의 안전성 을 고려 하여 잠 금 대상 이 노출 되 지 않도록 해 야 한다.많은 소스 라 이브 러 리 에서 사용 하 는 동기 화 방법 블록 은 object 설정 을 통 해 이 루어 집 니 다.비록 그것 은 여전히 반 사 를 통 해 풀 수 있 지만.그러나 보장 과 인위적인 오 작 동 으로 인 한 자물쇠 가 있 을 수 있다.

좋은 웹페이지 즐겨찾기