김태균과 Don Dodge

1. 김태균 "일본찍고 ML가겠다" - 야구선수 김태균이 일본에 진출한다는 뉴스를 봤다. 그런데 뉴스 제목이 가관이다. 일본찍고 ML 간다니... WBC를 두 번이나 제패한 일본은 졸지에 마이너 리그 쯤이 되어 버렸다. 기자의 전형적인 낚시짓일런지도 모르겠지만 만에 하나라도 정말 김태균이 저런 뉘앙스의 인터뷰를 했다면 대략 난감이다. '니덜은 그저 잠시 스쳐가는 인연일 뿐이여...'라는 생각으로 휘두르는 방망이로 홈런을 수십 번 친들 그게 팬들의 사랑으로 이어질 수 있을지 모르겠다. 게다가 설령 김태균이 정말 저런 말을 한 게 아니고 단지 기자의 낚시라 하더라도 김태균이 입단한다는 자바 롯데의 팬들이 이 소식을 들으면 퍽이나 좋아하겠다. 

2. Thanks Microsoft, Hello Google - MS에서 짤린 Don Dodge 라는 사람이 Google에 들어갔다고 블로그에 글을 올렸다. 짤린게 어지간히 억울했나보다. MS에서 만든 아웃룩, 오피스, IE 등등은 아주 쉣이고 구글에서 만든 지메일, 크롬, 안드로이드 등은 킹왕짱이란다. 이 사람이 누군지는 잘 모르겠지만 1,2년도 아니고 거의 5년 가까이 근무했던 회사를 이런 식으로 까고 새로 들어가는 회사 X구멍 빠는 글을 이렇게 장황하게 쓰는 것은 무척 인제스러워 보인다. 앞으로 몇 년 후 만약 이 사람이 구글에서 짤려서 다른 회사에 가게 된다면 그 때는 또 뭐라 할런지...

by silverbird | 2009/11/17 21:59 | 단상 | 트랙백 | 덧글(0)

무제

어쩌다 보니 몇 개월동안 블로그를 방치해두고 있었습니다.
그 동안 좀 바빴던 이유도 있지만 좀 더 근원을 따지자면 쓸게 별로 없더군요. 뭔가 프로그래밍에 대한 내용을 써볼까 싶으면 이미 남들이 잘 정리해 놓은 내용들이 많아 굳이 나까지 끄적일 필요가 없을 것 같고 그냥 가끔 떠오르는 단상을 정리해 볼까 하면 일에 정신이 팔려 글로 생각을 정리할 여유가 없고 뭐 그랬습니다.
근데 그러다보니 너무 글을 안쓰게 돼서 점점 머리가 굳는 것 같습니다. 하다못해 독후감이라도 써야 할 듯 싶습니다. 날도 추워지니 주말이면 밖에 나다니지 말고 집에 진득하니 앉아 블로그에 글이나 조금씩 써봐야 겠습니다.

by silverbird | 2009/11/12 20:25 | 기타등등 | 트랙백 | 덧글(2)

國 K1


...

by silverbird | 2009/07/28 12:30 | 단상 | 트랙백 | 덧글(3)

사람을 먹으면 왜 안되는가?


<이미지 출처: 알라딘>

 철학은 생각하는 학문이다. 이 세상에 생각이 필요없는 학문이 어디 있겠냐만은 다른 것들이 생각을 수단으로 이용하는 반면 철학은 생각 자체를 목적으로 한다는 점에서 다른 학문과 차이가 있다. 그래서 사람들은 철학을 '메타 학문' 이라 부르기도 한다.
 그러나 아쉽게도 우리가 학교에서 배운 철학은 철저한 암기 과목이었다. 심지어 과목명도 '도덕' 혹은 '국민윤리' 였지만 물론 전혀 도덕적이지 못한 선생 밑에서 절대 윤리적인 방식이라 볼 수 없는 방법으로 배워야 했다. 
 그러다 보니 정작 철학은 온데간데 없이 단지 흄이니 키에르케고르니 보드리야르니 하는 발음하기도 힘든 철학자 이름을 달달 외워야 했고 성선설을 주장한게 맹자인지 순자인지 헷갈려 시험 때마다 연필을 굴려야 했으며 왜 에피쿠로스 학파는 에피쿠로스가 창시했는데 스토아 학파는 스토아가 창시하지 않았는지 중간 고사 채점 때마다 분을 삼켜야 했다. 

 요는 이렇다. 철학은 위에서 말한 그런 철학자나 그들의 이론을 들먹여야만 철학이 아니다. 철학은 생각의 학문이고 따라서 모든 것에 의심을 갖고 질문을 던지는 것이 철학의 본질이다. 그런 면에서 사실 우리는 매일 철학을 실천하고 있다. 오늘도 수많은 블로거들이 다른 이들의 글에서 별 시덥잖아 보이는 사항 하나 하나에 댓글로 딴지를 걸고 있다. 그저 그냥 아무 생각없이 넘어가줘도 별 상관없을 것 같은 이야기에 '님 그건 성급한 일반화의 오류인것 같네요...' 뭐 이렇게 이죽거리지 않는가? 그렇다! 철학은 쉽게 말하면 딴지를 학문적으로 승화한 것이다.

 이 책은 지금껏 많은 철학자들이 걸었던 유명한 딴지(이 책에서는 이것을 철학 퍼즐이라고 점잖게 표현하지만)들 중 일부를 소개한 책이다. 일단 구성이 독특하다. 어린 시절 즐겨 읽었던 스토리형 퍼즐책('A를 선택했다면 53 페이지, B를 선택했다면 72 페이지로 가시오' 라는 식의 지문이 달린 책) 과 유사한 방식을 취했다. 그래서 윤리, 논리, 형이상학 등의 다양한 주제를 연관된 챕터 별로 쫓아가며 읽는 재미가 있다.
 내용 면에서는 헌혈이나 장기 기증, 태반크림 등과 굶주림을 면하기 위한 식인 행위의 차이는 무엇인지, 1년 동안 호위호식하던 칠면조가 그 동안의 경험을 통해 크리스마스 이브날에도 주인이 주는 먹이를 기대했다가 먹음직스러운 구이로 재탄생하는 반전 동화에 나오는 귀납 추리의 오류라든지, 내가 보는 빨간색과 남이 보는 빨간색이 정말 같은 색깔이라는 것을 어떻게 증명할 것인지, 시간은 정말 흘러가는 것인지 등등의 많은 철학적 질문들을 예화와 함께 비교적 어렵지 않게 풀어나간다. 

 사실 이런 책 하나 읽는다고 사람이 철학적이 되는 것은 아닐게다. 아니 '철학적' 이라는 말도 좀 우습다. 다만 2시간 정도 읽고 나면 그만인 그저 그런 책들 보단 좀 더 긴 시간을 즐길 수 있는 재미있는 책임에는 분명하다. 게다가 가끔은 이런 책을 통해서 딴지의 내공을 쌓아놔야 극장에서 '대한 뉘우스'를 보며 낄낄거리는 단무지는 안되지 않겠나 싶다. 요컨데 똥인지 된장인지는 구별하고 쌈싸먹는 인간이 되자는 말이다.

 p.s. 책의 뒷 표지에 이 책을 읽고 나면 '저녁 식탁 위에 활기찬 논쟁이 불꽃처럼 피어날 것이다.' 라는 추천사가 있던데 글쎄... 저녁 식탁에서 '사람을 먹으면 왜 안되는가?' 에 대해서 토론 했다가는 앞으로 고기 반찬 볼 일이 별로 없을 듯 싶다.

by silverbird | 2009/06/28 21:35 | 내가 읽은 책들 | 트랙백 | 덧글(6)

가장 보통의 존재



그대에게 난 가장 보통의 존재...추억조차 남지 않았겠지
나에게 그댄 가장 고통의 존재...

by silverbird | 2009/06/06 19:04 | 단상 | 트랙백 | 덧글(0)

블로그 하나 더 개설했습니다.

워낙에 천성이 게으른 탓에 한동안 블로그에 글을 쓰지 못했습니다. 
근래들어 회사에서 하는 일도 그렇고 해서 병렬/분산 프로그래밍에 관심을 갖고 공부를 하고 있습니다. 그러다보니 공부하고 적용한 내용들을 정리하려고 따로 블로그를 하나 만들었습니다. 새로 만든 블로그는 http://parallel.textcube.com/ 입니다.
이글루는 워낙에 잡다하게 끄적이다 보니 차분히 내용을 정리하기에는 힘들것 같더군요. 앞으로도 여기는 특정 주제에 치우치지 않고 그저 한번씩 끄적이고 싶을 때마다 애용할 생각입니다.
암튼 뭐 그렇다구요...

by silverbird | 2009/06/05 23:35 | 기타등등 | 트랙백 | 덧글(2)

자바 병행 프로그래밍 시 실수하기 쉬운 문제들

http://stackoverflow.com/questions/461896/what-is-the-most-frequent-concurrency-problem-youve-encountered-in-java

 원문 제목 그대로 자바에서 병행 프로그래밍을 할 때 자주 발생하는 문제들을 나열해 놓았습니다. 제가 이 블로그에서 언급했던 내용도 있고 어처구니없는 실수도 있고 정확히 알고 있지 않으면 착각하기 쉬운 것도 있고 어쨌든 한번쯤 훝어보고 상기해 볼만한 내용입니다.
 참고로 제가 최근에 했던 실수는 이것...

final CountDownLatch latcher = new CountDownLatch(n);
for (int i = 0; i < n; ++i) {
    executorService.submit(new Runnable() {
        public void run() {
            ...
            latcher.countDown();
        }
    });
}
latcher.wait();

흑...ㅜㅡ

 p.s. 혹시 CountDownLatcher 에 대해 모르시는 분이 있을까봐 첨언하자면 이름처럼 객체 생성 시 카운트다운 갯수를 지정하고 특정 조건에 이를때마다 카운트다운을 해서 0 에 이르면 빗장(latch) 를 엽니다. java.util.concurrent 패키지에 있습니다. 역시 같은 패키지에 있는 CyclicBarrier 와 함께, 기존의 notify(), wait() 를 대체할 수 있는 조건 동기화 클래스입니다. 원래 빗장이 열릴 때까지 기다리는 함수는 await() 인데 이게 wait() 함수랑 헷갈려요...

by silverbird | 2009/03/30 21:40 | 프로그래밍 | 트랙백 | 덧글(0)

잘 모르면 제발 가만히 있어라

배열 접근 연산자 operator[] 를 사용하는 것이 성능을 저하 시킨다는 내용이 effective STL 에 나왔던걸로 기억하는데요. at 을 사용하시는 걸 고려하시는게 좋을것 같습니다. 2005년도부터 Visual Studio 의 STL 라이브러리에서 at 을 사용할때 범위 체크를 해서 예외도 던져 줬던걸로 기억합니다.

둘다 오래전 기억들이라 정확치 않군요... ^^;

 - 오래전 기억이라 정확하지 않으면 그냥 답글 달지 말아라. 정 아는체 하고 싶으면 다시 찾아보던가...그저 몇 분만 투자해서 STL 책을 찾아 보거나 vector 코드를 살펴보거나(STL 코드는 템플릿이라 구현 소스를 다 볼 수 있다.) 직접 테스트 프로그램을 만들어 보거나 그것도 싫으면 검색해보면 될 것을 왜 정확치 않은 기억을 토대로 시간 낭비해가면서 반대로 가르쳐주는지 모르겠다.


하지만 동적으로 생성하시는분들도 있다. 이경우 클래스가 자기 자신의 포인트 형을
캡슐화된 형태로 가지고 있다가 객체 접근용 함수에서 NULL을 검사하고 생성해주고
접근하는 형태를 띄게 되는데 이경우는 객체 접근용 함수외에도 객체의 소멸용 함수를
하나더 만들어 주어야 한다. 하지만 동적할당으로 생성된 객체를 delete로 소멸시키려 접근한다면
delete는 또다시 소멸자를 호출하게 되면서 무한 재귀 함수로 빠져들게된다.
소스코드가 여기서 최소 약 5줄가량 늘어나며 무책임한 에러를 뱉어내기 시작한다.
선택은 자유지만 간편하며 안전한게 좋지 않을까?

소스를 직접 올리는 행위는 하지 않겠다.

 - 무한 재귀 함수에 빠져드는지 그렇지 않은지 잠깐만 자기 컴퓨터로 확인해보고 저런 말을 하기 바란다. 소스를 직접 올리는 행위를 하지 않는건 프로그래밍을 못하기 때문은 아닌지 의심된다.


뭐니뭐니해도 최고는 이것...

 - 쓰레드에 관한 글인데 전체적으로 워낙 오류가 많고 개판이라 잘못된 부분만 따로 발췌하기도 불가능한 수준이다.

-> 한빛 미디어 관계자 분이 이 글을 봤는지 그 사이에 해당 글이 없어졌다(정말 다행스러운 일이다). 하지만 불행하게도 누군가 저 글을 퍼가는 바람에 잔재가 남았다는 거...http://blog.naver.com/ki3ki7/80056924730 이 링크 글도 하루 빨리 인터넷 세상에서 사라지길 바란다.  

사람은 누구나 실수도 하고 착각도 하고 그래서 어지간하면 저런 거 못본척 넘어가는데 오늘따라 유난히 눈에 거슬리더라...자신들이 올린 잘못된 내용을 지식으로 삼아 고생할 사람들 생각은 안하나? 이런 무책임한 사람들 같으니라고...

p.s. 그리고 프로그래밍 관련 글쓰면서 구구절절 글로만 설명하고 소스는 귀찮아서 생략한다는 사람들...글쓰는 것보다 프로그래밍이 귀찮으면 그냥 프로그래밍 하지마...

by silverbird | 2009/03/26 19:00 | 단상 | 트랙백(1) | 덧글(12)

대학 신입생을 위한 추천 도서

2009 대학 새내기 추천도서
블로거가 고른 2009 새내기 추천도서

 추천 도서라는 것은 무엇보다 추천 받은 사람이 실제 읽어야 그 가치가 있는 법이다. 그런데 한국 간행물 윤리 위원회에서 추천한 목록은 아무리 봐도 평균 수준의 대학 신입생이 읽기에는 무리가 있어 보인다. 그리고 특정 전공을 지칭한 것도 아니고 일반 대학 새내기를 대상으로 한다면 최소한 다양한 분야를 포괄적으로 다룰려는 노력을 보여야 하지 않을까? 무엇보다 추천 목록을 아무리 봐도 그저 '에헴...이 정도는 읽어줘야 자고로 지성인이라 불릴만 하지...' 정도의 지적 허영심 외에는 추천 이유를 찾기 힘들다.

 각설하고 비판이 있었으면 대안을 제시해야 하는 법이다. 그런 의미에서 아이추판다님이 블로거들의 추천 목록을 만들어 보자는 제안을 했다. 내 깜냥에 모든 분야를 어우르는 추천 목록을 만들기는 불가능하지만 적어도 내가 지금껏 읽은 책 중에 대학 신입생이 읽기에 괜찮아 보이는 책들은 다음과 같다.

1. '플라톤 향연' - 조안 스파르, 문학동네


 비록 플라톤의 향연은 많은 번역본이 있지만, 중간 중간 내용에 어울리면서도 위트넘치는 삽화가 다른 책과는 다른 특별함을 준다. 그 나이 또래면 가장 관심있는 주제일 '사랑' 에 대해서 그리스 철학자들의 재기넘치는 사유를 엿볼 수 있다. 이 책을 읽으면 '아, 철학적 사유를 이렇게 재밌게 할 수도 있구나.' 하는 생각이 든다.

2. 변경 - 렁청진, 더난 출판사


 이 책을 한마디로 표현하면 '현대판 사기 열전' 이라 할 수 있다. 비록 최근에 나온 책이기에 '사기 열전'만큼 높이 평가받지는 못하지만 내 생각엔 이 책이 '사기 열전'보다 더 낫다. 그 이유는 첫 째, 시대적 한계로 인해 '사기 열전'에서는 다루지 못하는 사마천 이후의 다양한 인물들의 이야기를 많이 다루고 있다(솔직히 '사기 열전' 이야기는 이미 다른 곳에서 지겹게 접해서 진부한 면이 없지 않아 있다). 둘 째, 보다 현대 상황에 맞게 인물들을 해석하고 있다. 셋 째, 주제별로 더 체계적으로 정리되어 있다.
 우리가 역사를 공부하는 것은 과거를 통해 현대를 살아가는 지혜를 배우기 위함일 것이다. 역시 같은 이유로 과거 인물들의 살아온 방식에 관심을 갖는 것은 그들의 삶과 인성을 통해서 내가 어떻게 살아가야 할 것인가 하는 처세를 익히기 위함일 것이다. 그런 의미에서 이제 어설프게나마 사회를 접하게 될 대학 신입생에게 이 책 만큼 적합한 추천 도서가 있을까?

3. 과학 철학 입문 - 루돌프 카르납, 서광사


 윤리 위원회 추천 목록 중에 토마스 쿤의 '과학 혁명의 구조'가 있더라. 물론 그 책이 훌륭한 책이라는 점엔 이견이 없지만 훌륭한 책이 반드시 초보자에게도 훌륭한 책은 아니다. '과학 혁명의 구조'는 내가 보기엔 전혀 대학 신입생에게 어울리는 책이 아닐 뿐더러 이 책의 번역본은 정말 최악의 번역을 자랑한다. '과학 철학'이란 용어 조차 생소할 이들에게 자칫 '역시 철학이란 말이 들어가면 어렵고 따분해' 라는 인식을 심어줄까 두렵다. 
 물론 카르납의 '과학철학입문'도 그다지 쉬운 책은 아니다. 그럼에도 불구하고 이 책을 추천하는 이유는 그만큼 이 책을 읽을 필요가 있다고 느끼기 때문이다. 첫머리에서부터 과학에 대해 명쾌한 정의를 내리면서 시작하고 있는 이 책은, 단순히 과학을 암기 과목처럼 접했던 신입생들에게 이보다 더 적합한 과학 철학 소개서는 없다 할만하다. 게다가 요즘처럼 사이비가 판치고 출처가 의심스러운 정보가 들끓는 세상엔 이 책처럼 좋은 지침서가 될 만한 '과학철학서'를 읽을 필요가 있다.

4. 설득의 논리학 - 김용규, 웅진 지식 하우스


 논리적 사고는 학교 공부를 함에 있어서도 필요하지만 졸업하고 회사에 나가면 더욱 절실해지는 능력이다. 개인적으론 고등학교 때 수학과 국어 수업 시간을 한 시간씩 줄이고 대신 논리학을 일주일에 두 시간 정도씩 따로 가르쳤으면 하는 생각을 한다(예전부터 그렇게 했었다면 아마도 '100분 토론'이 지금처럼 짜증나는 프로가 되지 않았을 것이다). 물론 그렇게 하면 수학과 국어를 가르치는데에도 큰 도움이 될 것이다. 
 이 책은 재미도 있고 쉽게 읽히면서 마냥 가볍지만은 않은 미덕을 갖고 있다.

5. 수, 과학의 언어 - 토비아스 단치히, 한승


 베르나르 베르베르의 단편 소설집 '나무'에는 17보다 큰 숫자가 무엇인지 알고자 평생을 정진하는 한 사제 기사의 이야기가 나온다. 그 소설 속 세상에서 사람들은 숫자에 대한 개념이 매우 원시적이어서 다 큰 어른도 10보다 큰 숫자를 아는 사람이 드물다. '이 무슨 바보같은 세상이 다있단 말인가' 하고 생각할 수 있겠지만, 그리고 단순히 작가의 상상력에서만 존재하는 세상이라고 치부할 수도 있겠지만 아마 이 책을 보면 그 생각이 달라질 것이다.
 이 책은 우리가 지금과 같은 높은 수준의 수학적 직관력을 갖기까지 얼마나 오랜 시간 어떤 과정을 거쳐 발전해 왔는지 흥미로운 내용을 담고 있다. 수학하면 '홍성대' 부터 떠올릴 대학 신입생들에게 색다른 시각을 선사할 좋은 책이다.

by silverbird | 2009/03/01 12:29 | 기타등등 | 트랙백 | 덧글(0)

자바 병행 프로그래밍 - 잘못된 락 객체 사용법

ConcurrentHashMap vs. HashTable 이란 글에서 아래와 같은 코드는 잘못된 방법일 뿐더러 위험한 방법이라고 했습니다.

class SharedData {
    private Integer intData = 0;
    private Boolean boolData = false;

    public int getInt() { synchronized (intData) { return intData; } }
    public void setInt(int n) { synchronized (intData) { intData = n; } }
    public boolean getBool() { synchronized (boolData) { return boolData; } }
    public void setBool(boolean b) { synchronized (boolData) { boolData = b; } }
}

 우선 잘못된 이유에 대해서 먼저 설명하자면 프로그래머의 의도와 달리 intData 나 boolData 객체는 동기화되지 않습니다. 그 이유는 setInt() 나 setBool() 함수가 호출될 때마다 락으로 사용되는 intData 나 boolData 객체가 변할 수 있는데 이런 경우 쓰레드들이 서로 다른 락에 접근하기 때문입니다. 예를 들어 다음과 같은 코드가 있다고 합시다.

public class SyncTest {
  static private Object lock = new Object();

  static class TestRunnable implements Runnable {
    @Override
    public void run() {
      try {
        synchronized (lock) {
          System.out.println("before sleep in thread");
          Thread.sleep(1000);
          System.out.println("after sleep in thread");
        }
      } catch (Interrupted Exception e) {
      }
    }
  }

  public static void main(String[] args) {
    ExecutorService threads = Executors.newFixedThreadPool(2);
    threads.submit(new TestRunnable());
    threads.submit(new TestRunnable());
    threads.shutdown();
    try {
      threads.awaitTermination(1, TimeUnit.MINUTES);
    } catch (InterruptedException e) {
    }
    System.exit(0);
  }
}

 위 코드를 실행시켜 보면 항상 아래처럼 출력됩니다.

before sleep in thread
after sleep in thread
before sleep in thread
after sleep in thread

그러나 위에 동기화 부분을 다음과 같이 고치면 문제가 발생합니다.

synchronized (lock) {
  lock = new Object(); // assigned another object to lock
  System.out.println("before sleep in thread");
  Thread.sleep(1000);
  System.out.println("after sleep in thread");
}

 lock 객체가 동기화 블럭내에서 다른 객체로 변경되었기 때문에 이후에 다른 쓰레드에서 lock 객체에 접근하면 더이상 쓰레드간 동기화 효과가 없습니다. 자바에서 모든 객체는 레퍼런스 객체입니다. 그런데 synchronized 블럭에서 동기화를 위해 참조하는 객체는 이 레퍼런스 객체가 아니라 레퍼런스 객체가 참조하고 있는 실제 객체입니다. 따라서 비록 같은 lock 객체라 하더라도 이 객체가 참조하는 실제 객체가 바뀌었기 때문에 쓰레드간 동기화는 깨지고 맙니다.

 이 글의 처음에 소개된 SharedData 클래스의 잘못된 점은 intData 나 boolData 가 setter 메소드에서 다른 값이 할당되는 순간 Auto boxing 에 의해 다른 객체를 참조하기 때문입니다. 그러므로 이 시점에 다른 쓰레드가 synchronized 블럭에 접근하게 되더라도 다른 객체에 접근하기 때문에 락이 해제될때까지 기다리지 않습니다. 따라서 어떤 경우라도 synchronized 블럭 내에서 락 객체의 참조값을 변경하지 말아야 합니다. 보통 이런 실수를 할 소지는 적습니다만 SharedData 클래스 예처럼 Auto boxing 이 발생하는 Integer, Boolean, Long 등과 같은 클래스를 사용할 때는 자칫 착각할 수 있습니다. 

 이제 SharedData 클래스의 동기화 방식이 위험한 이유에 대해서 설명하겠습니다. 우선 아래 코드를 보시기 바랍니다.

public class SyncTest {
  static private String lock = "This is a lock;

  static class TestRunnable implements Runnable {
    @Override
    public void run() {
      try {
        synchronized (lock) {
          System.out.println("before sleep in thread");
          Thread.sleep(1000);
          System.out.println("after sleep in thread");
        }
      } catch (Interrupted Exception e) {
      }
    }
  }

  public static void main(String[] args) {
    // 이전 코드와 동일...
  }
}

위 코드가 제대로 동작할까요? 
 - 예 그렇습니다.
그렇다면 좋은 방법일까요?
 - 아뇨 그렇지 않습니다(Joshua Bloch 말투 좀 흉내내 봤습니다).

그러면 왜 좋은 방법이 아닐까요? 왜냐하면 String 객체를 락으로 사용하는 것은 예기치 않은 dead lock 을 발생시키기 때문입니다. 예를 들어 아래 코드를 보시죠.

public class BadLockSample {
  static void main(String[] args) throws Exception {
    String lock = "This is a lock";
    synchronized (lock) {
      Future<String> future = Executors.newSingleThreadExecutor().submit(new Callable<String>() {
        @Override
        public String call() throws Exception {
          String anotherLock = "This is a lock";
          synchronized (anotherLock) {
            return "Result";
          }
        }
      });
      System.out.println(future.get());
    }
  }
}

 위 코드에서 메인 쓰레드와 Callable 클래스가 호출되는 쓰레드는 서로 다른 락 객체를 사용하고 있습니다만 실행시켜보면 데드락이 발생하여 프로그램이 종료하지 않습니다. 왜 그럴까요? 그 이유는 자바에서 문자열을 다른 객체와 달리 특별한 방식으로 관리 하기 때문입니다. 자바는 메모리를 절약하기 위해 컴파일 시점에 평가 가능한 문자열에 대해서 영구 메모리에 문자열을 저장하며 이 문자열을 참조하는 String 객체들은 명시적으로 new String() 을 사용해서 객체를 생성하지 않는한 같은 문자열일 경우 동일한 객체를 참조하게 됩니다(혹은 String.intern() 메소드를 호출하면 명시적으로 이런 처리가 가능합니다).
 결국 위에서 lock 과 anotherLock 은 다른 레퍼런스 객체이지만 동일한 상수 문자열을 참조하기 때문에 사실 동일한 객체나 마찬가지입니다. 따라서 위 프로그램의 메인 쓰레드와 Callable 쓰레드는 같은 락을 획득하려고 경쟁하기 때문에 데드락이 발생합니다. 
 그런데 이게 SharedData 클래스와 무슨 관계일까요? SharedData 에서는 String 이 아니라 Integer 와 Boolean 객체를 사용했고 이들 클래스는 Auto Boxing 에 의해 primitive type 값을 자동으로 해당 타입에 맞는 객체로 생성해줍니다. 따라서 String 에서처럼 같은 객체를 참조할 일은 없을 듯 싶습니다.
 하지만 실제로는 그렇지 않습니다. 왜냐하면 Integer 나 Boolean 같은 Wrapping type class 들은 성능 향상을 위해 몇몇 값들에 대해서는 매번 객체를 새로 생성하는 것이 아니라 미리 만들어 놓은 객체를 재 사용하기 때문입니다(이런 방식을 Flyweight pattern 이라고 합니다).
 따라서 SharedData 객체를 만약 아래와 같이 사용하게 되면 데드락이 발생합니다.

public static void main(String[] args) {
static void main(String[] args) throws Exception {
    Integer lock= 0;
    synchronized (lock) {
      Future<String> future = Executors.newSingleThreadExecutor().submit(new Callable<String>() {
        @Override
        public String call() throws Exception {
          return new SharedData().getInt();
        }
      });
      System.out.println(future.get());
    }
  }
}

 결론적으로 값 객체를 직접 락으로 사용하지 말아야 합니다. 꼭 값 객체를 별도의 락으로 동기화시키려면 java.util.concurrent.lock.ReentrantLock 같은 락 전용 클래스 객체를 사용하는 것이 좋습니다.

p.s. 노파심에서 언급하는 건데...혹여라도 ReentrantLock 을 아래처럼 사용하지는 마세요...

Lock lock = new ReentrantLock();
synchronized (lock) {
  ....
}

java.util.concurrent.lock.Lock 관련 클래스들의 올바른 사용법은 다음과 같습니다.

Lock lock = new ReentrantLock();
lock.lock();
try {
  ....
} finally {
  lock.unlock();
}

by silverbird | 2009/02/28 12:06 | 프로그래밍 | 트랙백 | 덧글(3)

<< 이전 페이지     다음 페이지 >>