스레드를 다룰 때 까다로운 것 중 하나는 lock이 대체 의도치 않게 어디에 걸렸지? 일 겁니다. 링크에서도 다루고 있으니, 한 번 정도는 읽어보셔도 도움이 많이 되실 듯 싶습니다.

 

 


 먼저, 예제 프로그램 1을 보겠습니다.

 

 

 worker1과 worker2는 간단한 일을 합니다. 5초동안 sleep을 하고 끝냅니다. 그리고, 5번째 줄과 15번째 줄에, na가 가리키고 있는 객체에 lock을 겁니다. 즉, lock을 거는 대상은, Worker1의 na가 가리키는 Object, Worker2의 na가 가리키는 Object입니다.

 

 

 다음에 Main 클래스는 그냥 Worker1과 Worker2를 돌리고, 끝날 때 까지 기다린 다음에, 프로그램이 끝날 때 까지 걸린 시간을 측정합니다. 이게 다입니다. 위 프로그램의 실행 결과는 어떻게 나올까요?

 

 

 10.017초가 나오는데요. Worker1이 수행되는 데 걸리는 시간 + 2가 수행되는 데 걸리는 시간 + a를 더한 값입니다. 왜 그럴까요? "c"와 같은 것들을 String literal이라고 합니다.

 

 

 이들은 특별한 Pool에 저장이 됩니다. 즉, a.na와 b.na는 같은 객체를 가리키고 있습니다. 즉, lock을 획득하고, 해제해야 하는 대상이 w1과 w2가 같습니다. 따라서, w1가 객체의 lock을 소유한 상태에서, w2가 객체의 lock을 요구한 경우에, w2는 block이 됩니다. 화장실이 1개가 있는데, 누군가 들어가 있는 상황을 생각하면 쉽겠습니다.

 

 worker1의 na와 worker2의 na가 같은 객체를 가리키고 있다는 것을 보시면 됩니다.

 

 

 그러면 이 경우에는 어떨까요? 하나는 new로 할당한 String을 가리키고, 다른 하나는 "chogahui05" 라는 리터럴을 가리킵니다.

 

 

 new String("chogahui05")는, 힙에 새롭게 객체를 생성합니다. 즉, worker1의 na가 가리키는 객체와 worker2의 na가 가리키는 문자열 리터럴은 다릅니다. worker1 a가 동기화 블록에 들어간 경우에, 파란색 객체에 대해서 lock을 획득합니다. 그 다음에, worker2의  b가 들어갈 때, 무엇에 대한 lock이 필요한가요? 노란색에 대한 것입니다. a는 파란색에 대한 것을 획득했지, 노란색에 대한 것을 획득한 것이 아닙니다. 따라서, a가 수행되는 도중에 b가 수행될 수 있습니다.

 

  

 수행 결과는 위와 같습니다. 리터럴을 synchronized 대상으로 삼을 때에는 조심해야 한다는 것 정도만 얻어도 되겠습니다.

 


 Integer는 어떨까요?

 

 예제 프로그램 3을 보겠습니다. 실행 결과가 어떻게 나올까요?

 

 

 5초 + 5초 + a가 나옵니다. 왜 그럴까요? Integer x = 1은, 내부적으로 valueOf라는 메서드를 호출합니다.

 

 

 valueOf 메서드는 인자로 넘어온 i가 Cache 범위 내에 들어오면 미리 캐시에 저장된 객체를 리턴합니다.

 

 

 그림으로 그려 보면 이런 상황입니다. Worker1의 na와 Worker2의 na가 같은 객체를 가리키고 있기 때문에, 한 스레드가 동기화 블록에 들어가 버린 상태에서, 다른 스레드가 동기화 블록에 들어가려고 하면, block이 되어 버립니다. (사실 Cache된 Integer는, 미리 생성된 무언가라고 봐도 됩니다. 이는 Integer 클래스 안에 있는 IntegerCache 클래스를 보시면 알 수 있습니다.)

 

 

 그러면 충분히 큰 수를 넣은 경우에는 어떨까요?

 

 

 이 때에는 5초 + a가 나옵니다. 캐시될 수 있는 범위를 넘어간 경우에는 new로 새로 생성된 객체를 리턴하기 때문입니다.

 

 

 이는 Integer 내부에 있는 IntegerCache에 나타나 있습니다. -128에서 127 범위에 있는 정수는 Cache가 되고 AutoBoxCacheMax 옵션을 설정해서 조절할 수 있다. value 값이 같지만, 다른 두 객체를 생성하기 위해서, 다음과 같이 하면 어떨까요?

 

 되게 큰 수를 할당하는 것은 그리 깔끔한 방법이 아닙니다.  value 값이 같은, 다른 두 객체를 생성하기 위한 제일 좋은 방법은 new로 할당하는 것입니다.