2011-08-24 2 views
3

몇 가지 멀티 스레드 취미 프로그램과 이전의 (공학/물리학) 연구에도 몇 편을 썼습니다. 그래서 나는 자신이 동기화/스레드 안전성 및 프리미티브, 평균 사용자가 JMM 및 여러 스레드 등을 사용하여 도전하고있는 것을 발견했습니다.Java : 스레드 공유 데이터를위한 프레임 워크

내가 필요한 것으로 발견되어 다른 스레드가 공유하는 클래스의 인스턴스 또는 정적 멤버를 표시하는 적절한 방법이 없습니다. . 그것에 대해 생각해보십시오. 우리는 개인/보호/공개와 같은 액세스 규칙과 getters/setter 및 많은 것을 명명하는 방법에 대한 규칙을 가지고 있습니다.

하지만 스레딩은 어떻게해야하나요? 변수를 스레드 공유로 표시하고 특정 규칙을 따르려면 어떻게해야합니까? 휘발성/원자 심판이 그 일을 할 수도 있지만 때로는 뮤텍스를 사용해야합니다. 그리고 수동으로 뭔가를 사용하는 것을 기억해야 할 때 ... 잊어 버릴 것입니다. :) - 어떤 시점에서.

나는 생각이 들었다. 나는 처음이 아니라는 것을 알았다. http://checkthread.org/example-threadsafe.html - 나중에 시도해 볼만한 꽤 괜찮은 코드 분석기가있는 것 같다. 필요.

그러나 처음 문제가 다시 발생합니다. 메시지 전달 프레임 워크보다 조금 더 낮은 레벨이 필요하고 원시 뮤텍스보다 조금 더 높은 레벨이 필요하다고 가정 해 봅시다 ... 우리는 ... 무엇을 가지고 있습니까?

기본적으로 내가 만든 것은 클래스 멤버를 공유 또는 비공유로 선언 할 수있게 해주는 일종의 순수 자바 슈퍼 프레임 워크입니다. 다음은

그것이 어떻게 사용될 수 있는지의 예입니다

public final void transmit(final byte[] data) { 
    shared.run(new SharedRunnable<AllThreadsVars, Object, Object>() { 

     @Override 
     public Object run(final AllThreadsVars sharedVariable, final Object input) { 
      try { 
       if (sharedVariable.socket.isConnected() && sharedVariable.os != null) { 
        sharedVariable.os.write(data); 
        sharedVariable.os.flush(); 
       } 
      } catch (final Exception e) { // Disconnected 
       setLastMessageAt(0); 
      } 
      return null; 
     } 
    }, null); 
} 
:

public class SimClient extends AbstractLooper { 

    private static final int DEFAULT_HEARTBEAT_TIMEOUT_MILLIS = 2000; 
    // Accessed by single threads only 
    private final SocketAddress socketAddress; 
    private final Parser parser; 
    private final Callback cb; 
    private final Heart heart; 
    private boolean lookingForFirstMsg = true; 
    private BufferedInputStream is; 
    // May be accessed by several threads (T*) 
    private final Shared<AllThreadsVars> shared = new Shared<>(new AllThreadsVars()); 

. 
. 
. 
. 

    static class AllThreadsVars { 

     public boolean connected = false; 
     public Socket socket = new Socket(); 
     public BufferedOutputStream os = null; 
     public long lastMessageAt = 0; 
    } 

그리고 스레드 당신이 공유 객체에 대한 실행 가능한 같은 펑터를 전송해야 공유로 표시된 변수에 액세스 할 수

공유 실행 파일은 다음과 같이 정의됩니다.

어디로가는가? 글쎄,이 변수는 변수가 아니라 변수를 스레드 공유로 표시 할 수있는 도움을 준다. (예, 누출 될 수는 있지만 그 가능성은 낮다.) 일단 컴파일이 끝나면 컴파일 타임에이를 보장한다. 은 어떤 방법을 동기화하려면을 잊어 버릴 수 없습니다. 또한 컴파일 타임에 가능한 교착 상태를 찾기위한 테스트를 표준화하고 수행 할 수 있습니다 (단, 위의 프레임 워크로 컴파일 할 때 런타임에 구현 한 것만으로도 자바 컴파일러 이상을 필요로합니다).

기본적으로이 기능은 나에게 매우 유용하며 여기 바퀴를 다시 만들면이 기능이 제대로 작동하지 않을지 궁금해하고 있습니다. 그리고 나는 정말로 누구에게 물을 지 모릅니다. (오, 그래 및 공유 .RUN (는 SharedRunnable R, INPUT 입력) 단지이 그것이 정말 어떤 방법으로 완료되지 그래서 그냥 내 자신의 실험이다

private final <OUTPUT, INPUT> OUTPUT run(final SharedRunnable<SHARED_TYPE, INPUT, OUTPUT> r, final INPUT input) { 
    try { 
     lock.lock(); 
     return r.run(sharedVariable, input); 
    } finally { 
     lock.unlock(); 
    } 
} 

처럼 작동하지만 난 괜찮은 하나가 현재 프로젝트를 사용하고 있으며 실제로 많은 도움을줍니다.

+0

여기에 질문이 있습니까? – Daniel

+3

나는 당신의 예제를 이해하지 못한다고 생각하지만 ** 공유 변수 **는 동시성을 다룰 때 ** 당신이 원하지 않는 ** 것입니다. 잠금을 사용하는 공유 변수는 느리게 움직이고, 잠금 대기를 위해 더 많은 시간을 낭비하며, 일반적으로 응답이 적고 교착 상태에 빠지게합니다. 실제 동시성에 도달하는 가장 좋은 방법은 공유 상태가 전혀없는 것입니다. –

+0

네,하지만 애플리케이션의 어느 시점에서 여러 개의 쓰레드가 필요하다면 메시지 큐 이건 다른 것이 든 공유 변수가 필요합니다. 내 아이디어는 임의의 원자와 비슷한 연산을 구성하는 방법을 갖는 것입니다 (중요 : 공유 표시 상태에서 컴파일 타임에 사용을 강제하는 것). 또한 모든 스레드가 표준화 된 프레임 워크를 사용하기 때문에 너무 많은 노력을 기울이지 않고 교착 상태 분석 도구를 작성할 수있었습니다. 나는 이것의 다소 단순한 변종을 이미 썼다. 그리고 내 코드에서 잠재적 인 교착 상태 장소를 감지 할 수 있었다. – gigurra

답변

4

this과 같은 의미입니까?(findbugs과 같은 도구로 시행 할 수 있습니다.)

+0

예, 그런 것 같습니다. 고마워요. 내 자신을 사용하면 코드 분석 도구가 필요 없어 컴파일러만으로도 충분하지만 net.jcip.annotations는 매우 멋지다. :) 그 코드를 사용할지 아니면 내 코드를 사용할지 결정하기 전에 계약이 어떻게 작동 하는지를 읽어야 할 것입니다. – gigurra

0

값을 공유해야하는 경우 가장 좋은 방법은 클래스 내에 캡슐화하는 것입니다. 이렇게하면 호출자는 사용중인 스레드 모델을 알아야합니다. 내부적으로 사용되는 모델을 알고 싶으면 소스를 읽을 수 있지만 호출자는 모든 메소드가 스레드로부터 안전하기 때문에 ConcurrentMap (예를 들어)에 올바르게 액세스하는 것을 잊을 수 없습니다.

+0

문제는 미리 정의 된 동기화 된 컬렉션에서 추가/제거하는 것보다 더 많은 작업을 동기화해야 할 필요가 있다는 것입니다. 지도, 깃발, 타임 스탬프가 있다고 가정 해 보겠습니다. public void foo() { if (flag == ...) { modify (map); setTimeStamp(); flag = newValue; } } 여기 내 생각에 모든 공유 변수와 전체 작업을 동기화 된 것으로 캡슐화합니다. 그리고 동기화를 시행하기 위해 캡슐화 클래스에서조차도 그것을 잊지 않습니다. 동기화 된 방법으로는 충분하지 않습니다. 잊을 수 있습니다. – gigurra

+1

yuo가 캡슐화 클래스의 새로운 동작을 구현하거나 확장하는 경우에도 컴파일 타임에 강제 적용되지 않는 한 스레드 안전 동작을 유지하는 것을 잊기 쉽습니다. 나는 내 솔루션이 그다지 최선이라고 말하지는 않는다. 그러나 비슷한 방식으로 이전에 이루어 졌던대로 (jtahlborn과 checkthread를 본다.) 나는 완전히 잘못되었다고 생각하지 않는다. 그래도이 응용 프로그램을 필요 없도록 응용 프로그램을 다시 디자인하려고 할 수 있습니다. 결국 메시지 전달이 나아질 것입니다. 모든 사람들의 의견을 보내 주셔서 감사합니다. 지금이 질문을 어떻게 닫을 지 알아야합니다 :). – gigurra

+0

다른 모든 구성 요소를 사용하는 구성 요소가 스레드 안전 방식이어야하는 경우 캡슐화를 사용하여 모든 동기화 요구 사항을 중앙에서 관리 할 수 ​​있습니다. 이렇게하면 코드를 간단하게 유지할 수 있습니다. 잠금을 노출하면 더 강력하지만 위험하기 때문에 많은 동시성 라이브러리가 의도적으로이 잠금을 숨 깁니다. –

관련 문제