Sync의 동시화 Java

Sync의 동시화 Java?

In Java, 동기화는 여러 스레드가 공유 리소스에 액세스하는 것을 제어하는 ​​기능을 말합니다. 이는 하나의 스레드만 공유 리소스에 액세스하도록 허용하려는 경우 이상적인 옵션입니다.

이러한 실행 접근 방식은 일반적으로 '비동기' 프로그래밍이라고 합니다. 이러한 프로세서에는 또한 명령을 동시에 실행할 수 있는 가벼운 프로세스인 스레드가 있습니다.

유형 Sync정시화

동기화 방법에는 두 가지 유형이 있습니다. Java:

1) 프로세스 동기화

2) 스레드 동기화.

Thread를 공부해보자 프로세스 동기화 상세히.

프로세스 동기화: 프로그램 간의 동기화를 관리합니다. 예를 들어, `와 같은 프로그램Microsoft Word` 및 `Acrobat reader`는 개별 프로세스로 실행됩니다.

스레드 동기화: 두 개 이상의 스레드가 중요한 리소스를 동시에 실행하는 것을 스레드라고 합니다. Sync동시화. 상호 배타적 및 스레드 간 통신으로 더 그룹화할 수 있습니다.

잠금이란 무엇입니까? Java?

가두어 넣다 Java 모니터 또는 잠금 장치로 알려진 내부 엔터티를 중심으로 구축됩니다. 모든 객체에는 연관된 잠금이 있습니다. 따라서 객체 필드에 대한 일관된 액세스가 필요한 스레드는 객체 필드에 액세스하기 전에 객체 잠금을 획득해야 하며 작업이 완료되면 잠금을 해제합니다. 이렇게 하면 한 번에 하나의 스레드만 공유 데이터에 액세스할 수 있습니다.

동기화를 갖춘 멀티스레드 프로그램

멀티스레드 프로그램 `synchronized` 키워드를 사용하여 지정된 동일한 리소스를 공유하는 다른 스레드의 간섭으로부터 보호되는 메서드 또는 블록입니다.

동기화된 방법을 사용하여

동기화된 것으로 선언된 모든 메서드는 동기화된 메서드라고 합니다. 또한 공유 리소스에 대한 객체를 잠그는 데 사용됩니다. 따라서 스레드가 동기화된 메서드를 호출하면 해당 객체에 대한 잠금을 자동으로 점유하고 작업을 완료하면 해제합니다.

참고 : synchronized 키워드는 클래스와 변수와 함께 작동할 수 없습니다. 메서드와 블록만 키워드와 함께 사용할 수 있습니다.

왜 사용 Sync동기화된 방법?

  • 공유 리소스에 대한 개체를 잠그는 데 사용됩니다.
  • 동기화된 메서드가 호출될 때마다 객체는 잠금을 얻습니다.
  • 스레드가 해당 기능을 완료할 때까지 잠금이 해제되지 않습니다.

구문 :

Acess_modifiers synchronized return_type method_name (Method_Parameters) {
}
class MathService {
    synchronized void getSumOfArray(int[] numbers) {
     int sum = 0;

         for (int number : numbers) {
             System.out.println(Thread.currentThread()
                     .getName()
                     + " adds "
                     + sum + " to "
                     + number + " to get -> "
                     + (sum += number));

             try {
                 Thread.sleep(500);
             } catch (InterruptedException e) {
                 throw new RuntimeException(e);
             }
         }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
    }
}

코드 설명:

이 예제를 실행하고 '0' 스레드가 먼저 'mathService' 개체의 잠금을 가져오고 실행이 완료될 때까지 이 잠금을 독점적으로 사용하는 것을 관찰하세요. 이 코드에서는 스레드 '0'과 '1'이 인터리브되지 않습니다. 출력은 아래와 같습니다.

출력:

Thread-0 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63

동기화된 블록 사용

전체 메서드를 동기화하지 않으려고 가정해 보겠습니다. 대신 몇 줄의 코드를 동기화하려고 합니다. 그 당시에는 Synchronized 블록은 선택된 블록을 동기화하는 데 도움이 됩니다. Java 암호. Sync동기화된 메서드 잠금은 메서드에서 액세스되는 반면, 동기화된 블록 잠금은 객체에서 액세스됩니다.

class MathService {
    void getSumOfArray(int[] numbers) {
        synchronized (this){
            int sum = 0;

            for (int number : numbers) {
                System.out.println(Thread.currentThread()
                        .getName()
                        + " adds "
                        + sum + " to "
                        + number + " to get -> "
                        + (sum += number));

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
    }
}

코드 설명 :

이 코드를 실행하면 아무런 간섭 없이 작동한다는 것을 알 수 있습니다. 동기화된 메서드에서 잠금은 메서드에 의해 적용되지만 동기화된 블록에서 잠금은 객체에 의해 적용됩니다. 출력이 아래에 표시된 것과 같은지 확인하십시오.

출력:

Thread-0 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63

코드 설명:

이 코드를 실행하면 간섭 없이 작동한다는 것을 알 수 있는데, 이는 우리가 기대했던 것입니다. 동기화된 메서드에서 잠금은 메서드에 의해 적용되지만 동기화된 블록 메서드에서 잠금은 객체에 의해 적용됩니다.

정적 동기화 사용

In Java 동기화, 두 개 이상의 객체가 있는 경우 두 개의 스레드가 잠금을 획득하고 동기화된 블록이나 블록에 들어갈 수 있으며, 각 객체에 대해 별도의 잠금이 있습니다. 이를 방지하기 위해 정적 동기화를 사용할 수 있습니다. Synchronized 키워드는 정적 메소드보다 먼저 사용됩니다.

참고 : 정적 동기화에서 잠금 액세스는 객체나 메서드가 아닌 클래스에 있습니다.

여러 객체 잠금 문제를 보여주는 코드

class MathService {
    synchronized void getSumOfArray(int[] numbers) {
            int sum = 0;

            for (int number : numbers) {
                System.out.println(Thread.currentThread()
                        .getName()
                        + " adds "
                        + sum + " to "
                        + number + " to get -> "
                        + (sum += number));

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();
        MathService mathService1 = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));
        Thread threadThree = new Thread(() ->
                mathService1.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadFour = new Thread(() ->
                mathService1.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
        threadThree.start();
        threadFour.start();
    }
}

코드 설명:

'MathService'의 또 다른 인스턴스를 만들 때 스레드가 두 개체와 인터리브되므로 스레드에 간섭이 발생합니다. '0' 스레드와 '2' 스레드는 두 개체와 인터리브되고, 스레드 '1'과 '3'은 두 개체와 인터리브됩니다.

출력:

Thread-0 adds 0 to 10 to get -> 10
Thread-2 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-2 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-2 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-3 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-3 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63
Thread-3 adds 41 to 22 to get -> 63

동기화된 정적 메서드를 사용하는 동일한 코드

class MathService {
    synchronized static void getSumOfArray(int[] numbers) {
            int sum = 0;

            for (int number : numbers) {
                System.out.println(Thread.currentThread()
                        .getName()
                        + " adds "
                        + sum + " to "
                        + number + " to get -> "
                        + (sum += number));

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();
        MathService mathService1 = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));
        Thread threadThree = new Thread(() ->
                mathService1.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadFour = new Thread(() ->
                mathService1.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
        threadThree.start();
        threadFour.start();
    }
}

위의 코드를 실행하고 이제 스레드 간섭이 제거되었음을 확인하세요. 코드의 출력은 아래와 같습니다.

출력:

Thread-0 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-3 adds 0 to 20 to get -> 20
Thread-3 adds 20 to 21 to get -> 41
Thread-3 adds 41 to 22 to get -> 63
Thread-2 adds 0 to 10 to get -> 10
Thread-2 adds 10 to 11 to get -> 21
Thread-2 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63

동기화를 사용하는 장점

동시 애플리케이션으로 작업할 때의 이점은 다음과 같습니다.

  • 동기화의 주요 목적은 Java 스레드 간섭을 방지하여 데이터의 불일치를 방지하는 것입니다.
  • 동기화된 키워드 Java 잠금 기능을 제공하여 공유 리소스에 대한 상호 배타적 액세스를 보장하고 데이터 경쟁을 방지합니다.
  • 또한 코드 명령문의 순서가 바뀌는 것을 방지합니다. 컴파일러, volatile이나 synchronized 키워드를 사용하지 않으면 미묘한 동시성 문제가 발생할 수 있습니다.
  • Synchronized 키워드는 잠금을 해제할 때 캐시가 아닌 주 메모리에서 데이터를 읽습니다.
  • 또한 주 메모리에서 쓰기 작업을 플러시하여 메모리 불일치 오류를 제거합니다.

단점 Sync동시화 메커니즘

Sync동기화 메커니즘의 성능이 저하되었습니다.

예를 들어

  • A1, A2, A3, A4, A5라는 XNUMX개의 프로세스가 있다고 가정합니다.
  • 그들은 공유 리소스가 한 번에 하나의 스레드에 액세스하기를 기다리고 있습니다.
  • 모든 프로세스는 계속 대기하므로 대기열의 마지막 프로세스는 다른 모든 프로세스가 완료될 때까지 기다려야 합니다.

요약

  • Synchronization은 공유 리소스에 대한 여러 스레드의 액세스를 제어하는 ​​기능을 나타냅니다.
  • Java 동기화 방법에는 두 가지 유형이 있습니다. 1) 프로세스 동기화 및 2) 스레드 동기화.
  • 가두어 넣다 Java 모니터 또는 잠금 장치로 알려진 내부 엔터티를 중심으로 구축됩니다.
  • 멀티스레드 프로그램은 `synchronized` 키워드를 사용하여 지정된 동일한 리소스를 공유하는 다른 스레드의 간섭으로부터 보호되는 메서드 또는 블록입니다.
  • 동기화로 선언된 모든 메소드는 동기화 메소드라고 합니다.
  • In Java동기화된 메서드 잠금은 메서드에서 액세스되는 반면, 동기화된 블록 잠금은 객체에서 액세스됩니다.
  • 정적 동기화에서 잠금 액세스는 객체나 메서드가 아닌 클래스에 있습니다.
  • 동기화의 주요 목적은 Java 스레드 간섭을 방지하여 데이터의 불일치를 방지하는 것입니다.
  • 이 방법의 가장 큰 단점은 모든 프로세스가 대기 상태로 유지되므로 대기열의 마지막 프로세스가 다른 모든 프로세스가 완료될 때까지 기다려야 한다는 것입니다.