>  기사  >  Java  >  동기화의 4가지 기능을 살펴보겠습니다.

동기화의 4가지 기능을 살펴보겠습니다.

青灯夜游
青灯夜游앞으로
2020-07-07 16:15:502975검색

동기화의 4가지 기능을 살펴보겠습니다.

1. 동기화된 잠금 재진입

1.1 소개

동기화된 키워드에는 동기화된 잠금 재진입 기능이 있습니다. 즉, 동기화를 사용할 때 스레드가 객체 잠금을 얻을 때 다음을 수행할 수 있습니다. 객체 잠금을 다시 요청하면 객체 잠금을 다시 가져옵니다. 이는 동기화된 메서드/블록 내에서 이 클래스의 다른 동기화된 메서드/블록을 호출할 때 항상 잠금을 얻을 수 있음을 보여줍니다.

예:

public class Service1 {

    public synchronized void method1(){
        System.out.println("method1");
        method2();
    }

    public synchronized void method2(){
        System.out.println("method2");
        method3();
    }

    public synchronized void method3(){
        System.out.println("method3");
    }

}
public class MyThread extends Thread {

    @Override
    public void run(){
        Service1 service1 = new Service1();
        service1.method1();
    }


    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}

실행 결과는 다음과 같습니다.
동기화의 4가지 기능을 살펴보겠습니다.
☹ 이 결과를 보고 어리둥절했습니다. 재진입 가능한 자물쇠라는 것을 어떻게 증명할 수 있을까요?
➤ "재진입 잠금"의 개념은 자체 내부 잠금을 다시 획득할 수 있다는 것입니다. 예를 들어 스레드가 객체에 대한 잠금을 획득할 때 객체 잠금이 해제되지 않았습니다. 다시 잠그면 잠금이 잠겨 있어도 개체를 계속 얻을 수 있습니다. 잠금을 재진입할 수 없으면 교착 상태가 발생합니다.
➤ "재진입 잠금"의 가장 큰 역할은 교착 상태를 방지하는 것입니다

1.2 분석

프로그램에서 동기화 모니터의 잠금은 명시적으로 해제될 수 없지만, 프로그램 잠금은 다음 상황에서 해제됩니다.
① 현재 스레드의 동기화된 메서드 또는 코드 블록이 실행을 종료할 때 해제됩니다.
② 현재 스레드가 코드 블록 또는 메서드를 종료하기 위해 중단 또는 반환을 만났을 때 해제됩니다.
3 처리되지 않은 오류 또는 예외가 발생하고 비정상적으로 종료됩니다
4 프로그램이 동기화 개체 대기 메서드를 실행하고 현재 스레드가 일시 중지되고 잠금이 해제됩니다

그러면 위 프로그램에서 스레드가 동기화 메서드 method1에 진입하면 다음을 얻습니다. Service1 잠금의 객체이지만, method1 실행 시 동기화 메서드 method2가 호출되는 경우 일반적인 상황에서는 동기화 메서드 method2 실행 시에도 개체 잠금을 획득해야 합니다. 현재 method1의 개체 잠금이 해제되지 않았습니다. 이로 인해 교착 상태가 발생하고 method2를 계속 실행할 수 없습니다. 하지만 위 코드의 실행 결과로 볼 때, method2와 method3은 정상적으로 실행이 가능하다는 뜻인데, 이는 다른 동기식 메서드나 코드 블록 내에서 이 클래스의 코드 블록이나 다른 동기식 메서드를 호출할 때 항상 잠금이 걸렸다는 뜻입니다 .

1.3 부모-자식 상속 가능성

부모-자식 클래스 상속 환경에서는 재진입 잠금이 지원됩니다. 샘플 코드는 다음과 같습니다.

public class Service2 {
    public int i = 10;
    public synchronized void mainMethod(){
        i--;
        System.out.println("main print i="+i);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Service3 extends Service2 {

    public synchronized void subMethod(){
        try{
            while (i>0){
                i--;
                System.out.println("sub print i= "+i);
                Thread.sleep(100);
                this.mainMethod();
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
public class MyThread extends Thread {

    @Override
    public void run(){
        Service3 service3 = new Service3();
        service3.subMethod();
    }


    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}

실행 결과는 다음과 같습니다.


동기화의 4가지 기능을 살펴보겠습니다.이 프로그램은 설명합니다. 부모-자식 클래스 상속 관계가 있는 경우 하위 클래스는 "재진입 잠금"을 통해 부모 클래스의 동기화 메서드를 완전히 호출할 수 있습니다.

2. 예외가 발생하면 잠금이 자동으로 해제됩니다.

스레드에서 실행되는 코드에서 예외가 발생하면 해당 스레드가 보유한 잠금이 자동으로 해제됩니다.

인증코드는 다음과 같습니다.

public class Service4 {

    public synchronized void testMethod(){
        if(Thread.currentThread().getName().equals("a")){
            System.out.println("ThreadName= "+Thread.currentThread().getName()+" run beginTime="+System.currentTimeMillis());
            int i=1;
            while (i == 1){
                if((""+Math.random()).substring(0,8).equals("0.123456")){
                    System.out.println("ThreadName= "+Thread.currentThread().getName()+" run exceptionTime="+System.currentTimeMillis());
                  //Integer.parseInt("a");
                }
            }
        }else{
            System.out.println("Thread B run time= "+System.currentTimeMillis());
        }
    }
}
public class ThreadA extends Thread{

    private Service4 service4;

    public ThreadA(Service4 service4){
        this.service4 = service4;
    }

    @Override
    public void run(){
        service4.testMethod();
    }
}
public class ThreadB extends Thread{

    private Service4 service4;

    public ThreadB(Service4 service4){
        this.service4 = service4;
    }

    @Override
    public void run(){
        service4.testMethod();
    }
}
public class Main {
    public static void main(String[] args) {
        try {
            Service4 service4 = new Service4();

            ThreadA a = new ThreadA(service4);
            a.setName("a");
            a.start();

            Thread.sleep(500);

            ThreadB b = new ThreadB(service4);
            b.setName("b");
            b.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

참고로 Service4 클래스의

Integer.parseInt("a");는 현재 Annotation된 상태이며, 실행 결과는 다음과 같습니다.
동기화의 4가지 기능을 살펴보겠습니다.Since 스레드 a에는 오류가 없지만(true), 현재 스레드 a는 무한 루프에 있고 잠금은 항상 a에 의해 점유되어 스레드 b는 잠금을 얻을 수 없습니다. 즉 스레드 b를 실행할 수 없습니다.

Service4 클래스에서

Integer.parseInt("a"); 주석 처리를 해제하면 실행 결과는 다음과 같습니다.

동기화의 4가지 기능을 살펴보겠습니다. 
스레드 a에서 오류가 발생하면 스레드 b가 잠금을 획득하여 실행할 수 있습니다. 메소드에서 예외가 발생하면 잠금이 자동으로 해제됩니다.

3. 모든 객체를 모니터로 사용

Java는 "모든 객체"를 "객체 모니터"로 동기화하는 기능을 지원합니다. 이러한 "임의 개체"의 대부분은 인스턴스 변수 및 메서드 매개 변수이며 형식은 동기화된(이 개체 x가 아님) 동기화 코드 블록입니다.

샘플 코드는 다음과 같습니다.

public class StringLock {

    private String lock = "lock";

    public void method(){
        synchronized (lock){
            try {
                System.out.println("当前线程: "+Thread.currentThread().getName() + "开始");
                Thread.sleep(1000);
                System.out.println("当前线程: "+Thread.currentThread().getName() + "结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        final StringLock stringLock = new StringLock();
        new Thread(new Runnable() {
            @Override
            public void run() {
                stringLock.method();
            }
        },"t1").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                stringLock.method();
            }
        },"t2").start();
    }
}

실행 결과는 다음과 같습니다.


동기화의 4가지 기능을 살펴보겠습니다.이 개체가 아닌 개체를 잠그면 특정 이점이 있습니다. 클래스에 동기화된 메서드가 많으면 동기화가 가능하더라도 차단됩니다. , 따라서 작업이 영향을 받습니다. 그러나 동기화된 코드 블록을 사용하여 this가 아닌 개체를 잠그면 동기화된(this가 아닌) 코드 블록의 프로그램 및 동기화 방법이 비동기화되고 다른 개체는 이 동기화를 잠급니다. 이 잠금 장치에 대해 경쟁하는 방법이 허용되지 않으므로 운영 효율성이 크게 향상될 수 있습니다.

4. 동기화에는 상속이 없습니다.

동기화 키워드를 추가하지 않고 하위 클래스에 다시 작성하면 상위 클래스의 동기화 메서드가 동기화되지 않으므로 하위 클래스의 메서드에 동기화를 추가해야 합니다. 키워드.

추천 학습: Java 비디오 튜토리얼

위 내용은 동기화의 4가지 기능을 살펴보겠습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제