읽기만 하는 쓰레드와 쓰기만 하는 쓰레드, 단 두 개만 있다고 해도 예측할 수 없는 문제가 발생할 수 있습니다.
예를 들면 쓰기(put)가 완료되지 않은 부분을 읽기(get) 시도하는 문제죠.
(제가 ArrayList 내부 구조를 모르기 때문에 이 예시가 정확한 문제 사례가 아닐 수도 있습니다.)
참고로 Vector 는 thread-safe 이기 때문에 질문자께서 말씀하신 구조에 더 적합할 것 같습니다.
물론 읽기 전용 쓰레드에서는 현재 데이터가 하나라도 존재하는지(isEmpty)는 확인한 후에 get 해야겠죠 :)
질문자께서 locking 이라고 표현하신 것은 아무래도 blocking 을 말씀하시는 것 같습니다.
위에 neocoin 님이 말씀하신 CopyOnWriteArrayList 가 한 가지 해결책입니다.
read 쓰레드가 한 개, write 쓰레드 한 개 라면 아무런 locking 이 필요없고, 각 쓰레드는 block 되지 않습니다.
구현을 정확히는 모르겠지만, addnull님이 말씀하신 implicit lock도 필요없을 것 같습니다. volatile 변수만 가지고도 구현 가능할 것 같습니다.
write 쓰레드가 한 개 이상이라면 write 작업 중에는 block 될 수 있습니다.
문제는 write가 자주 일어날 경우에 비용이 크다는 점이지요.
write가 자주 일어나지 않고, non-blocking 행동이 필요하다면 고려할만한 해결책입니다.
http://docs.oracle.com/javase
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CopyOnWriteArrayList.html
예상할 수 없는 오류가 발생할 수 있습니다.
ArrayList 는 thread-compatible 이기 때문에,
(참고 http://www.ibm.com/developerworks/java/library/j-jtp09263/index.html )
읽기만 하는 쓰레드와 쓰기만 하는 쓰레드, 단 두 개만 있다고 해도 예측할 수 없는 문제가 발생할 수 있습니다.
예를 들면 쓰기(put)가 완료되지 않은 부분을 읽기(get) 시도하는 문제죠.
(제가 ArrayList 내부 구조를 모르기 때문에 이 예시가 정확한 문제 사례가 아닐 수도 있습니다.)
참고로 Vector 는 thread-safe 이기 때문에 질문자께서 말씀하신 구조에 더 적합할 것 같습니다.
물론 읽기 전용 쓰레드에서는 현재 데이터가 하나라도 존재하는지(isEmpty)는 확인한 후에 get 해야겠죠 :)
Vector는 "두쓰레드는 arraylist에 대한
Vector는 "두쓰레드는 arraylist에 대한 lock이걸리면 안됩니다." 는 조건을 만족할 수 없습니다.
thread-safe 라는건
thread-safe 라는건
lock을 걸지 않은 상태에서 여러 쓰레드가 해당 자료구조의 데이터 수정(add, remove, put, get 등..)을 해도 안전하다는 의미입니다.
예를 들면 5byte 데이터를 쓰고 읽는 작업이 두 쓰레드에서 따로 행해질때,
thread-safe일 경우에 5byte가 온전히 다 쓰여지거나 읽혀지는게 보장되는데,
thread-safe가 보장 안 되면,
쓰는 작업이 5byte 중에 2~3byte만 완료된 상황에서도 다른 쓰레드의 읽기 작업이 실행될 수 있습니다.
질문자께서 원하시는 상황이 명시적인 lock이 없는 상황에서
하나의 쓰레드는 get만 다른 하나의 쓰레드에서는 put만 하시고 싶으시다면
thread-safe 자료구조를 쓰시는게 맞을 것 같습니다 :)
방금 댓글 달고 다시 생각해보니
방금 댓글 달고 다시 생각해보니
저는 "synchronized 키워드를 사용한 explicit lock을 사용하지 않겠다"라는 의미로만 생각하고 이야기했습니다.
혹시 thread-safe 자료구조에서 사용하는 implicit lock도 없어야한다고 생각하신 거라면,
그런 조건에서 안전한 작업을 보장하는 방법은 없다고 생각됩니다.
질문자께서 locking 이라고 표현하신 것은
질문자께서 locking 이라고 표현하신 것은 아무래도 blocking 을 말씀하시는 것 같습니다.
위에 neocoin 님이 말씀하신 CopyOnWriteArrayList 가 한 가지 해결책입니다.
read 쓰레드가 한 개, write 쓰레드 한 개 라면 아무런 locking 이 필요없고, 각 쓰레드는 block 되지 않습니다.
구현을 정확히는 모르겠지만, addnull님이 말씀하신 implicit lock도 필요없을 것 같습니다. volatile 변수만 가지고도 구현 가능할 것 같습니다.
write 쓰레드가 한 개 이상이라면 write 작업 중에는 block 될 수 있습니다.
문제는 write가 자주 일어날 경우에 비용이 크다는 점이지요.
write가 자주 일어나지 않고, non-blocking 행동이 필요하다면 고려할만한 해결책입니다.
음.. 왜 "수정" 버튼이 안 보이지요? 뭐
음.. 왜 "수정" 버튼이 안 보이지요? 뭐 여하튼,
> thread-safe가 보장 안 되면, 쓰는 작업이 5byte 중에 2~3byte만 완료된 상황에서도 다른 쓰레드의 읽기 작업이 실행될 수 있습니다.
단순히 이를 위해서라면 자바 메모리 모델에서는 volatile 변수에 대한 write 면 충분합니다.
굳이 synchronize 를 사용해서 lock을 할 필요는 없습니다.
CopyOnWriteArrayList 도 이를 이용해서 구현된 것이구요.
아 그렇군요!
volatile 변수가 있었군요. 하나 배워갑니다 ㅎㅎ
volatile 변수에 대해서 좀 더 찾아봤습니다.
질문자께서 원하시는 mutlithread 환경에서 atomic get and set operation의 정상 동작을 보장하려면 자바 버전 5 이상을 사용하셔야합니다.
volatile 변수 원 의미(C와 C++에서)는 메모리에 직접 데이터를 쓰고 읽겠다는 뜻이고,
자바 5 이후부터는 이 의미를 확장해서 atomic operation들의 happens-before relationship이 된다고 합니다.
volatile 변수를 사용하지 말아야할 때는 복합 연산(complex operation)할 때라고 합니다.
http://www.javamex.com/tutorials/synchronization_volatile_dangers.shtml
이런 경우엔 lock을 사용하지 않고선 synchronize 문제를 피해갈 수 없겠죠 :)
http://www.java2s.com/Code/Ja
http://www.java2s.com/Code/Java/Threads/Producer-Consumer.htm
원하시는 답은 아니지만
Producer-Consumer 패턴 사용하시면 좋을것같은데요?
흘러가고있는 지금 이 시간에 충실하자.
java.util.concurrent 패키지를 사용
lock이 걸리면 안된다는 게 무슨 의도로 하신 말씀인지 모르겠습니다만, 적절한 동기화 작업(synchronized)없이 서로 다른 쓰레드가 자료를 공유하게 할 순 없습니다. 이에 관해서는 java concurrency 에 관련된 문서를 보시면 될 꺼구요.
그냥 두 스레드가 producer - consumer 구조로 작동하는 걸 구현하려는 것이면 java.util.concurrent.BlockingQueue 인터페이스를 구현한 것들을 사용하시는 게 좋아보이네요.
...
Java는 잘 모릅니다만, 찾아보니까 이런 게 있네요. 혹시 원하시는 게 이런거?
http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html
댓글 달기