2013-02-13 4 views
6

나는 모든 정적 메소드가 자바 웹 애플리케이션의 맥락에서 synchronized이어야한다고 말한 친구가있다. 그게 사실이야? 이것에 관한 많은 다른 스택 오버플로 페이지를 읽었습니다.Java : 모든 정적 메소드를 동기화해야합니까?

  1. 다중 스레드 (A Sevlet 컨테이너에서와 같이 스레드 풀과) 스레드 간의
  2. 공유 데이터, 여부
  3. 단일 클래스 로더 : 내가 믿게 한 것은 당신이 가지고있는 경우에만 동기화 할 필요가있다 세션 데이터 또는 정적 구성원 데이터입니다.
  4. 공유 데이터는 변경 가능해야합니다. 읽기 전용 데이터는 공유 할 수 있습니다.

정적 멤버가 동기화되어야하지만 정적 메서드가 아니라고 생각합니다.

import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

public class ThreadTest { 

    static String staticString = ""; 

    // This static method is safe b/c it only uses local data. 
    // It does not use any shared mutable data. 
    // It even uses a string builder. 
    static String safeStaticMethod(String in) { 
     // This also proves that StringBuilder is safe 
     // When used locally by a thread. 
     StringBuilder sb = new StringBuilder(); 
     sb.append("Hello: "); 
     sb.append(in); 
     return sb.toString(); 
    } 

    // This static method is not safe b/c it updates and reads 
    // shared mutable data among threads. 
    // Adding synchronized will make this safe. 
    static String unsafeStaticMethod(String in) { 
     staticString = in; 
     StringBuffer sb = new StringBuffer(); 
     sb.append("Hello: "); 
     sb.append(staticString); 
     return sb.toString(); 
    } 

    public static void main(String[] args) { 
     ThreadTest test = new ThreadTest(); 
     test.staticMethodWithLocalData(); 
     test.staticMethodWithStaticData(); 
    } 

    public void staticMethodWithLocalData() { 

     ExecutorService executor = Executors.newFixedThreadPool(2); 
     final int iterations = 100000; 

     executor.submit(new Runnable() { 

      @Override 
      public void run() { 
       for (int index = 0; index < iterations; ++index) { 
        if (!safeStaticMethod("Thread1").equals("Hello: Thread1")) { 
         System.out.println("safeStaticMethod at " + index); 
        } 
       } 
      } 
     }); 

     executor.submit(new Runnable() { 

      @Override 
      public void run() { 
       for (int index = 0; index < iterations; ++index) { 
        if (!safeStaticMethod("Thread2").equals("Hello: Thread2")) { 
         System.out.println("safeStaticMethod at " + index); 
        } 
       } 
      } 
     }); 
    } 

    public void staticMethodWithStaticData() { 

     ExecutorService executor = Executors.newFixedThreadPool(2); 
     final int iterations = 100000; 

     executor.submit(new Runnable() { 

      @Override 
      public void run() { 
       for (int index = 0; index < iterations; ++index) { 
        if (!unsafeStaticMethod("Thread1").equals("Hello: Thread1")) { 
         System.out.println("unsafeStaticMethod at " + index); 
        } 
       } 
      } 
     }); 

     executor.submit(new Runnable() { 

      @Override 
      public void run() { 
       for (int index = 0; index < iterations; ++index) { 
        if (!unsafeStaticMethod("Thread2").equals("Hello: Thread2")) { 
         System.out.println("unsafeStaticMethod at " + index); 
        } 
       } 
      } 
     }); 
    } 
} 

이 코드가 핵심을 증명합니까?

편집 : 이것은 내가 포인트를 증명하기 위해 해킹 한 일부 쓸데없는 코드입니다.

+8

스레드 세이프 코드를 작성하는 것은 임의의 위치에서 '동기화 된'코드를 두드리는 것보다 훨씬 복잡합니다. – SLaks

+1

버퍼로 쓰레드가 공유되지 않기 때문에'safeStaticMethod'는'StringBuffer'를 사용하여 여전히 안전합니다. 특정 메소드 호출에 국한됩니다. – Charlie

+1

위의 내용을 자세히 설명하면 기본적으로 threadsafe 프로그램 작성에 보편적으로 유효한 "if X then Y"규칙은 없습니다. (대부분의 사람들은 불필요하게 응용 프로그램의 동시성을 줄입니다.) – millimoose

답변

9

아니요, 일부 정적 메서드를 동기화해야하는 것은 아닙니다. 당신의 목록은 내가 볼 수있는 한 기본적으로 완전합니다. 정적 메소드 중

  1. 정적 변경 가능한 부재, 또는
  2. 수정할 수있는 개체에 대한 참조를 전달되는 액세스 할 때 특히주의한다.

가 나는 synchronize가 이해되지 않는다 스레드하지 않고 있기 때문에 1 (처음에 스레드를 갖는), 전제 조건 인 것은 말할 필요도 없다 생각합니다.

2 번 들어 본 적이 없으므로 고려해야할지 확실하지 않습니다.

4

아니요. 그건 사실이 아니며 나는 그것이 해로울 것이라고 확신합니다. 모든 응용 프로그램이 동시에 실행될 필요는 없으며 동시성이 필요한 응용 프로그램에서도 모든 코드가 작동해야하는 것은 아닙니다.

더 많은 증거로, look at the source of String. 거기에는 많은 정적 메서드가 있지만 하나의 동기화 된 메서드 만 찾을 수 있으며 정적 메서드도 없습니다.

+2

문자열이 동기화되지 않는 한 String은 변경 불가능합니다. 이는 변경 불가능한 객체가 읽기 전용이므로 기본적으로 안전하기 때문입니다 (원래 질문의 4 번 항목). String은 실제로'synchronized'의 사용을 피하고 여전히 안전하도록 설계된 클래스의 가장 좋은 예제 중 하나입니다. – Matt

+2

네, 그렇습니다. 그는 포인트 4를 지적했지만 ** 모든 ** 정적 메소드를 동기화해야하는지에 대한 질문은 "아니오, 그렇지 않습니다." –

+1

아, 참으로. 나는 지금 이해한다 - 좋은 예 : – Matt

2

정적 메서드는 거의 이 아니며은 webapp에서 동기화되어야합니다. 100 % 확신하지 않는 한, 응용 프로그램을 사용할 유일한 사람은 3 인 회계 팀이며, 회사 전체에서 벗어나면 갑자기 갈기 갈기 찢어지면 얼굴이 붉어 질 것입니다.

글로벌 블로킹 공유 리소스를 만드는 것은 확장성에있어 완전히 실패했습니다! 또한 두통을 일으키고 응용 프로그램 서버를 클러스터링해야하는 경우 Terracotta 스타일의 솔루션을 사용할 가능성이 높습니다.

1

서블릿/JSP를 사용하는 하나의 빌드처럼 웹 애플리케이션에서 항상 다중 스레드 접근성이라는 철학에 도전 할 때 동기화 된 방법을 사용하지 않아야합니다. 따라서 동기화 된 블록 내에서 필요한 코드 만 하나씩 액세스해야합니다.

1

전혀 아님. 대체로 정적 메서드는 정적 변수를 수정하지 않으므로 이 동기화 될 필요가 없습니다.. 간단한 이해를 돕기 위하여

,

//sample static util method to get string in upper case  
    public static String getName(String name){ 
     return a.toUpperCase(); 
    } 
위의 방법은 스레드 1000 호출 할 수

아직이 방법은 단지 argument- 문자열 이름을 필요로하며, 그 때문에 스레드 안전 될 것입니다 스레드 스택에서. 스레드간에 데이터를 공유하지 않습니다.

모든 정적 메서드가 동기화되면 웹 응용 프로그램이 매우 느리고 사용하기에 힘이 없어야합니다. 단일 스레드가 메소드에 액세스하려고 할 때마다 클래스 레벨 잠금을 갖습니다.

JDK에서 제공하는 API에는 많은 정적 메소드가 있습니다. 모든 사람들이 동기화 되었다면 JAVA를 사용하지 않을 것입니다. 귀하의 경우

는 거기 정적 방법으로 수정되고있는 정적 변수 (클래스 레벨 변수). 예, 여러 스레드가 만들어지고 정적 메서드에 액세스하려고하면 스레드 간섭이 발생할 수 있습니다. 공유 데이터이 있으므로 스레드로부터 안전하지 않습니다.

대부분 정적 메서드는 전달되는 인수에 따라 유틸리티 함수입니다.

비 동기화 된 정적 메서드는 정적 클래스 변수을 수정하지 않으면 스레드로부터 안전합니다.

관련 문제