다중 스레드 동시성은 동기화된 문을 통해 JAVA에서 달성할 수 있습니다. JVM은 동기화된 코드 블록을 사용하여 하나의 스레드만 특정 객체에 대한 잠금을 동시에 보유할 수 있도록 보장합니다. 잠금 메커니즘을 사용하면 여러 스레드가 중요한 리소스에 안전하게 액세스할 수 있습니다.
동기화 코드는 다음과 같이 작성됩니다.
코드 1:
Object obj = new Object(); ... 동기화(obj) { //TODO: 중요한 리소스에 액세스} JAVA의 멀티스레딩은 항상 트랩으로 가득 차 있습니다. Boolean을 동기화된 객체로 사용하면 다음 두 가지 상황이 발생할 수 있습니다.
1. 하나의 객체가 잠겨 있다고 생각되지만 실제로는 서로 다른 객체가 동기화됩니다.
코드 2:
private 휘발성 Boolean isTrue = false; publich void aMethod() { ... synced(isTrue) { isTrue = !isTrue; //TODO: 중요한 리소스에 액세스 isTrue = !isTrue; 위의 코드는 얼핏 보면 아무런 문제가 없습니다. 동기화(isTrue)를 사용하기 때문에 동시에 하나의 스레드만 중요한 리소스에 접근할 수 있지만, 그렇지 않습니다. 두 상수 false와 true는 서로 다른 두 개체에 해당하기 때문입니다. isTrue가 변경되면 서로 다른 스레드가 서로 다른 개체를 동기화할 가능성이 높습니다. JAVA의 자동 박싱은 false를 Boolean.FALSE로 변경하고 true를 Boolean.TRUE로 변경합니다(이는 또한 false가 Boolean.FALSE로 변경되면 결과가 동일함을 보여줍니다). 위 상황 중 하나에 대한 테스트 코드를 다음과 같이 작성하세요.
코드 3:
public class BooleanTest { private 휘발성 Boolean isTrue = Boolean.FALSE; //여기서 false를 사용해도 마찬가지입니다. public void aMethod() { for(int i=0;i<10;i++) { Thread t = new Thread() { 공개 무효 실행() { 동기화(isTrue) { isTrue = !isTrue; System.out.println(Thread.currentThread().getName() + " - isTrue=" + isTrue); try{ Double ran = 1000 * Math.random(); Thread.sleep(ran.intValue()); }catch(InterruptedException e) {} if(!isTrue) System.out.println( Thread.currentThread().getName() + " - 아, 안 돼요!"); isTrue = !isTrue; t.start(); } } public static void main(String... args) { BooleanTest bt = new BooleanTest() } } 위의 코드를 실행하면 때때로 "-Oh, No!"가 표시되는데, 이는 서로 다른 스레드가 동시에 동기화된 코드 블록에 진입했음을 나타냅니다.
2. 서로 다른 객체가 동기화된 것으로 생각되지만 실제로는 하나의 객체입니다.
때로는 여러 객체에 대해 동기화를 원할 수도 있습니다. Boolean이 동기화된 객체로 사용되는 경우 관계가 없어야 하는 두 동기화 블록이 동일한 객체 잠금을 사용할 가능성이 높습니다. 예는 다음과 같습니다:
코드 4:
private 휘발성 Boolean aBoolean = Boolean.FALSE; private 휘발성 Boolean anotherBoolean = false; public void aMethod() { ... 동기화(aBoolean) { //TODO: 중요 리소스 액세스 1 } ... } public void anotherMethod() { . .. 동기화(anotherBoolean) { //TODO: 중요 리소스 2에 액세스 } ... } 원래 aMethod와 anotherMethod가 관련되지 않은 두 스레드 세트에 의해 호출된다고 가정합니다. 그러나 Boolean.FALSE와 false는 동일한 개체를 가리키므로 중요 리소스 2에 대한 액세스가 중요 리소스 1에 의해 차단될 수 있습니다(그 반대의 경우도 마찬가지).
위의 두 가지 상황은 동기화된 블록을 사용할 때 부울 객체를 동기화된 객체로 사용하지 마십시오. 그렇지 않으면 예상치 못한 문제가 발생하거나 향후 코드 수정 시 트랩이 발생할 수 있음을 나타냅니다.
또한 상수의 동기화는 위험하다는 것을 알 수 있습니다. 부울을 동기화해야 하는 경우 new 연산자를 사용하여 부울 개체를 만들어야 합니다.