java 다중 루틴 프로그래밍 사용 Synchronized 키워드 동기화 방법


public synchronized void run()
{    
}
위의 코드를 통해 알 수 있듯이void와public 사이에synchronized 키워드를 추가하면run방법을 동기화할 수 있다. 즉, 같은 Java류의 대상 실례에 대해run방법은 동시에 하나의 라인에만 호출되고 현재의 run이 실행된 후에야 다른 라인에 호출될 수 있다.현재 라인이 run 방법의 yield 방법에 실행되었더라도 잠시 멈췄을 뿐입니다.다른 라인은run 방법을 실행할 수 없기 때문에, 최종적으로 현재의 라인이 계속 실행될 것입니다.먼저 다음 코드를 보십시오:sychronized 키워드는 대상의 실례와 연결됩니다

class Test
  {
        public synchronized void method()
       {

       }
  }

  public class Sync implements Runnable
  {
       private Test test;
       public void run()
       {
            test.method();
       }
       public Sync(Test test)
       {
           this.test = test;
       }
       public static void main(String[] args) throws Exception
       {
           Test test1 =  new Test();
           Test test2 =  new Test();
           Sync sync1 = new Sync(test1);
           Sync sync2 = new Sync(test2);
           new Thread(sync1).start();
           new Thread(sync2).start();
       }
   }
 
Test 클래스에서의 method 방법은 동기화됩니다.그러나 위의 코드는 두 개의 테스트 클래스의 실례를 세웠기 때문에test1과test2의 method 방법은 각각 실행된다.method를 동기화하려면 Sync 클래스의 실례를 만들 때 그 구조 방법에 같은 Test 클래스의 실례를 전달해야 합니다. 아래 코드에서 보듯이 Sync sync1 = new Sync(test1);synchronized를 사용하여 비정적 방법을 동기화할 수 있을 뿐만 아니라synchronized를 사용하여 정적 방법을 동기화할 수도 있다.메서드 방법을 다음과 같이 정의할 수 있습니다

class Test
{
    public static synchronized void method() {   }
}
Test 클래스의 객체 인스턴스는 다음과 같습니다. Test test = new Test ().정적 방법에 대해synchronized 키워드를 추가하면 이 방법은 동기화입니다. 테스트를 사용하든지.method(), 또는 Test를 사용합니다.method () 는 method 방법을 호출합니다. method는 모두 동기화되어 비정적 방법의 여러 가지 실례적인 문제가 존재하지 않습니다.23가지 디자인 모델 중의 단부품(Singleton) 모델은 전통적인 방법에 따라 디자인하면 라인이 안전하지 않다. 아래의 코드는 라인이 안전하지 않은 단부품 모델이다.

package test;

// Singleton
class Singleton
{
    private static Singleton sample;

    private Singleton()
    {
    }
    public static Singleton getInstance()
    {
        if (sample == null)
        {
            Thread.yield(); // Singleton
            sample = new Singleton();
        }
        return sample;
    }
}
public class MyThread extends Thread
{
    public void run()
    {
        Singleton singleton = Singleton.getInstance();
        System.out.println(singleton.hashCode());
    }
    public static void main(String[] args)
    {
        Thread threads[] = new Thread[5];
        for (int i = 0; i < threads.length; i++)
            threads[i] = new MyThread();
        for (int i = 0; i < threads.length; i++)
            threads[i].start();
    }
}

위의 코드에서 yield를 호출하는 방법은 단일 모드의 스레드가 안전하지 않다는 것을 나타내기 위해서이다. 만약에 이 줄을 없애면 위의 실현은 여전히 스레드가 안전하지 않고 나타날 가능성이 훨씬 적다.프로그램의 실행 결과는 다음과 같습니다

25358555
26399554
7051261
29855319
5383406
위의 운행 결과는 서로 다른 운행 환경에서 모두 같을 수 있지만 일반적으로 이 다섯 줄의 출력은 완전히 같지 않다.이 출력 결과를 통해 알 수 있듯이 get Instance 방법을 통해 얻은 대상 실례는 우리가 기대하는 것이 아니라 다섯 개이다.스레드가 Thread를 실행하기 때문입니다.yield() 이후 CPU 리소스를 다른 스레드에 전달합니다.스레드 사이를 전환할 때 Singleton 대상 실례를 만드는 문장이 실행되지 않았기 때문에 이 몇 개의 스레드가 if판단을 통과했기 때문에 다섯 개의 대상 실례를 만드는 상황이 발생했다(만들 수 있는 것은 네 개 또는 세 개의 대상 실례이다. 이것은 몇 개의 스레드가 Singleton 대상을 만들기 전에 if판단을 통과했느냐에 따라 실행할 때마다 결과가 달라질 수 있다).위의 단일 모드를 안전한 라인으로 만들려면 get Instance에synchronized 키워드를 추가하면 됩니다.코드는 다음과 같다. public static synchronized Singleton get Instance () {} 물론 더 간단한 방법은 Singleton 변수를 정의할 때 Singleton 대상을 만드는 것이다. 코드는 다음과 같다. private static final Singleton sample = new Singleton ().그리고 getInstance 방법에서 샘플을 직접 되돌려주면 됩니다.이런 방식은 간단하지만 getInstance 방법에서 Singleton 대상을 만드는 것이 유연한지 모르겠다.독자는 구체적인 수요에 따라 서로 다른 방법을 선택하여 단일 모델을 실현할 수 있다.
synchronized 키워드를 사용할 때 다음과 같은 네 가지 주의사항이 있습니다.
1. synchronized 키워드는 상속할 수 없습니다.synchronized를 사용하여 방법을 정의할 수 있지만synchronized는 방법 정의의 일부분에 속하지 않기 때문에synchronized 키워드는 계승될 수 없습니다.부류의 어떤 방법에서synchronized 키워드를 사용하고 부류에서 이 방법을 덮어쓰면, 부류의 이 방법은 기본적으로 동기화되지 않으며, 부류의 이 방법에synchronized 키워드를 현저하게 붙여야 합니다.물론 자류 방법에서 부류에 해당하는 방법을 호출할 수 있다. 그러면 자류 중의 방법은 동기화되지 않지만 자류는 부류의 동기화 방법을 호출했기 때문에 부류의 방법도 동기화에 해당한다.이 두 가지 방식의 예 코드는 다음과 같다. 하위 방법에synchronized 키워드를 추가한다

class Parent
{
    public synchronized void method() {   }
}
class Child extends Parent
{
    public synchronized void method() {   }
}
하위 클래스 방법에서 상위 클래스의 동기화 방법을 호출합니다

class Parent
{
    public synchronized void method() {   }
}
class Child extends Parent
{
    public void method() { super.method();   }
}
2. 인터페이스 방법을 정의할 때synchronized 키워드를 사용할 수 없습니다.3. 구조 방법은synchronized 키워드를 사용할 수 없지만 다음 부분에서 논의할 synchronized 블록을 사용하여 동기화할 수 있습니다.4. synchronized는 자유롭게 놓을 수 있다.앞의 예에서synchronized 키워드를 방법의 반환 형식 앞에 사용합니다.그러나 이것은synchronized가 유일하게 놓을 수 있는 위치가 아니다.비정적 방법에서synchronized는 방법 정의의 맨 앞에 놓을 수 있고, 정적 방법에서synchronized는static의 앞에 놓을 수 있다. 코드는 다음과 같다

public synchronized void method();
synchronized public void method();
public static synchronized void method();
public synchronized static void method();
synchronized public static void method();
그러나synchronized는 방법이 되돌아오는 형식의 뒤에 놓을 수 없습니다. 예를 들어 아래의 코드가 잘못되었습니다:

public void synchronized method();
public static void synchronized method();
synchronized 키워드는 동기화 방법만 사용할 수 있고 동기화 변수는 사용할 수 없습니다. 예를 들어 아래의 코드도 잘못되었습니다..

public synchronized int n = 0;
public static synchronized int n = 0;
synchronized 키워드 동기화 방법을 사용하는 것이 가장 안전한 동기화 방식이지만 synchronized 키워드를 대량으로 사용하면 불필요한 자원 소모와 성능 손실을 초래할 수 있다.표면적으로 보면synchronized가 잠그는 것은 하나의 방법이지만 실제로synchronized가 잠기는 것은 하나의 종류이다.즉, 비정상적인 방법인method1과method2가 정의되었을 때synchronized를 사용한다면,method1이 실행되기 전에method2는 실행할 수 없습니다.정적 방법과 비정적 방법의 상황은 유사하다.그러나 정태와 비정태 방법은 서로 영향을 주지 않는다.아래의 코드를 보십시오

package test;

public class MyThread1 extends Thread
{
    public String methodName;

    public static void method(String s)
    {
        System.out.println(s);
        while (true)

    }
    public synchronized void method1()
    {
        method(" method1 ");
    }
    public synchronized void method2()
    {
        method(" method2 ");
    }
    public static synchronized void method3()
    {
        method(" method3 ");
    }
    public static synchronized void method4()
    {
        method(" method4 ");
    }
    public void run()
    {
        try
        {
            getClass().getMethod(methodName).invoke(this);
        }
        catch (Exception e)
        {
        }
    }
    public static void main(String[] args) throws Exception
    {
        MyThread1 myThread1 = new MyThread1();
        for (int i = 1; i <= 4; i++)
        {
            myThread1.methodName = "method" + String.valueOf(i);
            new Thread(myThread1).start();
            sleep(100);
        }
    }
}

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

method1
method3
위의 운행 결과를 보면 method2와method4는method1과method3가 끝나기 전에 실행할 수 없습니다.따라서 클래스에서synchronized 키워드를 사용하여 비정적 방법을 정의하면 이 중의 모든synchronized 키워드를 사용하여 정의한 비정적 방법에 영향을 줄 수 있다는 결론을 얻을 수 있다.만약 정의된 것이 정적 방법이라면, 클래스에서synchronized 키워드로 정의된 정적 방법에 영향을 줄 것입니다.이것은 데이터 테이블의 시계 자물쇠와 같아서 기록을 수정할 때 시스템이 전체 시계를 잠그기 때문에 이런 동기화 방식을 대량으로 사용하면 프로그램의 성능을 대폭 떨어뜨릴 수 있다.

좋은 웹페이지 즐겨찾기