자바의synchronized 키워드를 깊이 이해하다

7108 단어 javasynchronized
synchronized 키워드는 이 방법을 대표하여 자물쇠를 채우는 것입니다. 어느 스레드 A가 이 방법에 실행될 때마다 이 방법을 사용하고 있는 다른 스레드 B(또는 C D 등)가 있는지 검사해야 합니다. 어떤 경우에는 이 방법을 사용하고 있는 스레드 B(또는 C D)가 이 방법을 실행한 후에 이 스레드 A를 실행해야 합니다. 없으면 두 가지 사용법을 포함합니다. 그것이 바로synchronized 방법과synchronized 블록입니다.
1.synchronized 방법: 방법 성명에 synchronized 키워드를 넣어synchronized 방법을 설명합니다.예:

public synchronized void accessVal(int newVal); 
synchronized 방법은 클래스 구성원 변수에 대한 접근을 제어합니다. 모든 클래스는 하나의 자물쇠에 대응하고, 모든 synchronized 방법은 반드시 이 방법을 호출하는 클래스 실례의 자물쇠를 얻어야 실행할 수 있습니다. 그렇지 않으면 소속 루트가 막힙니다. 방법이 실행되면 이 자물쇠를 독점하고 이 방법에서 돌아올 때까지 자물쇠를 방출합니다. 이후에 막힌 루트는 이 자물쇠를 얻어서 다시 실행 가능한 상태로 들어갈 수 있습니다.이러한 메커니즘은 같은 시각에 모든 클래스 실례에 대해synchronized라고 성명된 구성원 함수 중 하나는 실행 가능한 상태이기 때문에 (이 클래스 실례에 대응하는 자물쇠를 얻을 수 있기 때문에) 클래스 구성원 변수의 접근 충돌을 효과적으로 피할 수 있다. (클래스 구성원 변수에 접근할 수 있는 모든 방법이 synchronized라고 성명된다면)자바에서 클래스의 실례뿐만 아니라 모든 클래스도 자물쇠에 대응한다. 그러면 우리는 클래스의 정적 구성원 함수를synchronized로 성명하여 클래스의 정적 구성원 변수에 대한 접근을 제어할 수 있다.synchronized 방법의 결함: 만약에 큰 방법을synchronized라고 성명하면 효율에 큰 영향을 줄 수 있다. 전형적으로 라인 클래스의 방법run()을synchronized라고 성명하면 라인의 전체 생명 기간 동안 계속 실행되기 때문에 이 클래스의synchronized 방법에 대한 호출은 영원히 성공하지 못할 것이다.물론 우리는 접근 클래스 구성원 변수의 코드를 전문적인 방법에 넣어synchronized라고 설명하고 주 방법에서 호출해서 이 문제를 해결할 수 있지만, 자바는 우리에게 더 좋은 해결 방법을 제공했다. 그것이 바로synchronized 블록이다.
2.synchronized 블록:synchronized 키워드를 통해synchronized 블록을 설명합니다.구문은 다음과 같습니다.

synchronized(syncObject)
{  
//   
} 
synchronized 블록은 이러한 코드 블록이다. 그 중의 코드는 대상synchObject(전에서 말한 바와 같이 클래스 실례나 클래스일 수 있음)의 자물쇠를 얻어야 실행할 수 있고 구체적인 메커니즘은 앞에서 말한 것과 같다.임의의 코드 블록에 대해 임의로 지정할 수 있고 잠긴 대상을 임의로 지정할 수 있기 때문에 유연성이 비교적 높다.
synchronized (this)에 대한 이해다른 라인은 현재 라인이 이 코드 블록을 실행한 후에야 이 코드 블록을 실행할 수 있습니다.  
2. 하나의 라인이object의synchronized (this) 동기화 코드 블록에 접근할 때, 다른 라인이object의 모든 다른synchronized (this) 동기화 코드 블록에 대한 접근이 막힙니다.  
3. 그러나, 한 라인이object의synchronized(this) 동기화 코드 블록에 접근할 때, 다른 라인은 이object의synchronized(this) 동기화 코드 블록을 제외한 부분에 접근할 수 있습니다. 
넷째, 세 번째 예는 다른 동기화 코드 블록에도 적용된다.즉, 하나의 라인이object의synchronized (this) 동기화 코드 블록에 접근할 때, 이object의 대상 자물쇠를 얻을 수 있다.결과적으로 다른 라인이 이object 대상의 모든 동기화 코드 부분에 대한 접근이 일시적으로 막혔습니다.  
5. 상기 규칙은 다른 대상의 자물쇠에도 적용된다.
synchronized의 간단한 예

public class TextThread
{
/**
* @param args
*/
public static void main(String[] args)
{
// TODO
        TxtThread tt = new TxtThread();
        new Thread(tt).start();
        new Thread(tt).start();
        new Thread(tt).start();
        new Thread(tt).start();
}
}
class TxtThread implements Runnable
{
int num = 100;
String str = new String();
public void run()
{
while (true)
{
   synchronized(str)
   {
   if (num>0)
   {
    try
    {
     Thread.sleep(10);
    }
    catch(Exception e)
    {
     e.getMessage();
    }
    System.out.println(Thread.currentThread().getName()+ "this is "+ num--);
   }
   }
}
}
}
위의 예에서 시간차, 즉 잘못된 기회를 만들기 위해 Thread를 사용했습니다.sleep(10) 자바는 다중 스레드에 대한 지원과 동기화 메커니즘이 많은 사람들의 사랑을 받고 있다.synchronized 키워드를 사용하면 다중 스레드 공유 데이터 동기화 문제를 쉽게 해결할 수 있을 것 같다.도대체 어때요?DD는synchronized 키워드의 작용에 대해 깊이 있게 이해해야만 정론할 수 있다.
전반적으로 말하면synchronized 키워드는 함수의 수식자로도 사용할 수 있고 함수 내의 문장으로도 사용할 수 있다. 즉, 평소에 말한 동기화 방법과 동기화 문장 블록이다.더 자세한 분류를 하면synchronized는 instance 변수,objectreference(대상 인용),static 함수와classliterals(클래스 이름 글자 상량)에 작용할 수 있습니다.더 자세히 설명하기 전에 우리는 몇 가지를 명확하게 해야 한다.
A. synchronized 키워드를 방법에 추가하든 대상에 추가하든 간에 코드나 함수를 잠금 DD로 하는 것이 아니라 동기화 방법은 다른 라인의 대상에 접근할 수 있습니다.
B. 각 객체는 잠금(lock)만 연결됩니다.
C. 동기화를 실현하는 것은 매우 큰 시스템 비용을 대가로 하고 심지어 자물쇠가 사라질 수도 있기 때문에 가능한 한 무의미한 동기화 제어를 피해야 한다.
이어서synchronized가 서로 다른 곳에 사용되는 것이 코드에 미치는 영향에 대해 토론한다. 만약에 P1, P2가 같은 종류의 서로 다른 대상이라고 가정하면 이 클래스에서 다음과 같은 몇 가지 상황의 동기화 블록이나 동기화 방법을 정의하면 P1, P2는 모두 그것들을 호출할 수 있다.
1. synchronized를 함수 수식자로 사용할 때 예시 코드는 다음과 같다.

Public synchronized void methodAAA()
{
//…
}
이것이 바로 동기화 방법입니다. 그러면 이때synchronized가 잠긴 대상은 어느 대상입니까?그것이 잠긴 것은 이 동기화 방법을 호출하는 대상이다.즉, 하나의 대상 P1이 서로 다른 라인에서 이 동기화 방법을 실행할 때 그들 사이에는 상호 배척이 형성되어 동기화 효과를 얻을 수 있다.그러나 이 대상이 속한 클래스에서 발생하는 다른 대상 P2는synchronized 키워드가 추가된 방법을 임의로 호출할 수 있습니다.위의 예제 코드는 다음과 같습니다.

public void methodAAA()
{
synchronized (this)      // (1)
{
       //…..
}
}
(1)처의this가 가리키는 것은 무엇입니까?그것은 P1과 같은 이 방법을 호출하는 대상을 가리킨다.동기화 방법은 실질적으로synchronized를objectreference에 작용하는 것을 볼 수 있다.DD는 P1 대상의 자물쇠를 가져와야 P1의 동기화 방법을 호출할 수 있다. 그러나 P2의 경우 P1이라는 자물쇠는 그것과 전혀 상관이 없고 프로그램도 이런 상황에서 동기화 메커니즘의 통제에서 벗어나 데이터의 혼란을 초래할 수 있다.
2. 다음과 같은 예제 코드로 블록을 동기화합니다.

public void method3(SomeObject so)
{
    synchronized(so)
    {
       //…..
    }
}
이때 자물쇠는 so라는 대상이다. 이 자물쇠를 받은 사람이 제어하는 코드를 실행할 수 있다.명확한 대상이 자물쇠로 되어 있을 때 프로그램을 이렇게 쓸 수 있지만, 명확한 대상이 자물쇠로 되어 있지 않고 코드를 동기화하려고 할 때 특수한 instance 변수를 만들어서 자물쇠로 사용할 수 있다.

class Foo implements Runnable
{
        private byte[] lock = new byte[0]; // instance
        Public void methodA()
        {
           synchronized(lock) { //… }
        }
        //…..
}
주: 0 길이의byte 수조 대상을 만들면 그 어떤 대상보다 경제적인 DD 보기 컴파일된 바이트 코드: 0 길이의byte[] 대상을 생성하려면 3개의 조작 코드만 필요하고, Objectlock=new Object()는 7줄의 조작 코드가 필요합니다.
3. synchronized를 static 함수에 적용하고 예시 코드는 다음과 같다.

Class Foo
{
    public synchronized static void methodAAA()   // static
    {
        //….
    }
    public void methodBBB()
    {
       synchronized(Foo.class)   // class literal( )
    }
}
코드 중의methodBBB() 방법은classliteral을 자물쇠로 하는 경우입니다. 동기화된static 함수와 같은 효과를 냅니다. 얻은 자물쇠는 매우 특별합니다. 현재 이 방법을 호출하는 대상이 속하는 클래스입니다.
'Effective Java'라는 책에서 장푸를 봤던 기억이 납니다.class와 P1.getClass () 는 동기화 자물쇠에 사용되는 것과 다르기 때문에 P1을 사용할 수 없습니다.이 클래스를 잠그는 목적을 달성하기 위해 getClass () 를 사용합니다.P1은 Foo 클래스에서 생성된 객체를 나타냅니다.추정할 수 있다. 만약에 하나의 클래스에서synchronized의static 함수 A를 정의하고synchronized의instance 함수 B를 정의한다면 이 클래스의 같은 대상인 Obj는 다중 노드에서 각각 A와 B 두 가지 방법에 접근할 때 동기화를 구성하지 않는다. 왜냐하면 그들의 자물쇠가 모두 다르기 때문이다.A방법의 자물쇠는 Obj라는 대상이고 B의 자물쇠는 Obj가 속한 그 Class이다.
소결은 다음과 같습니다.
synchronized가 잠긴 대상이 어느 대상인지 파악하면 우리가 더욱 안전한 다중 루틴 프로그램을 설계하는 데 도움을 줄 수 있다.공유 자원에 대한 동기화 접근을 더욱 안전하게 할 수 있는 방법도 있습니다. 1. 프라이빗의 instance 변수 + get 방법을 정의하고public/protected의 instance 변수를 정의하지 마십시오.변수를public로 정의하면 대상은 외부에서 동기화 방법의 제어를 돌려 직접 그것을 얻고 변경할 수 있습니다.이것도 자바빈의 표준 실현 방식 중의 하나이다.2. 만약에 instance 변수가 하나의 대상, 예를 들어 수조나 ArrayList 같은 것이라면 상술한 방법은 여전히 안전하지 않다. 왜냐하면 외부 대상이 get 방법을 통해 이 instance 대상의 인용을 받은 후에 다른 대상을 가리키면 이private 변수도 변하고 위험하지 않기 때문이다.이 때 get 방법도synchronized 동기화를 추가하고 이private 대상의clone () DD만 되돌려야 합니다. 호출자에서 얻은 것은 대상 복사본의 인용입니다. 그리고 비교적 자주 사용하는 것은 다음과 같습니다. Collections.synchronizedMap(new HashMap(), 물론 이 MAP는 생명이 클래스에 있는 전역 변수입니다. 바로 라인이 안전한 HashMap입니다. 웹 응용 프로그램은 전체 웹 용기에서 공용하기 때문에 라인 보안을 사용하여 데이터의 정확성을 확보해야 합니다.

좋은 웹페이지 즐겨찾기