2016-06-09 2 views
1

문제점 : 100 개 이상의 스레드에서 동시에 액세스 할 수있는 고정 용량 (예 : 2 개 요소)의 컬렉션을 유지 관리하십시오.FIFO 순서로 고정 용량의 스레드 안전 수집

최근 스레드의 최신 요소를 항상 저장하십시오. 일단 저장되면, 모든 요소가 중복되는지 확인하는 메소드를 작성하십시오.

내 솔루션 : 고정 용량의 BlockingQueue 및 맞춤 추가 메소드 구현.

import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.ArrayBlockingQueue; 
import java.util.Iterator; 

public class FixedBlockingQueue<T extends Object> { 

    final BlockingQueue<T> queue; 
    private int capacity; 

    public FixedBlockingQueue(int capacity){ 
     super(); 
     this.capacity = capacity; 
     queue = new ArrayBlockingQueue<T>(capacity); 
     System.out.println("Capactiy:"+this.capacity); 
    } 
    public void addElement(T element){ 
     try{ 
      if (queue.size() > capacity - 1){ 
       queue.remove();   
      } 
      queue.put(element); 
      for (Iterator it = queue.iterator(); it.hasNext();){ 
       System.out.println(it.next()); 
      } 
      System.out.println("________"); 
     }catch(Exception err){ 
      err.printStackTrace(); 
     } 
    } 

    public static void main(String args[]){ 
     FixedBlockingQueue<Integer> f = new FixedBlockingQueue<Integer>(2); 
     for (int i=0; i< 10; i++){ 
      f.addElement(i); 
     } 

    } 
} 

출력 : 출력에서 ​​

0 
________ 
0 
1 
________ 
1 
2 
________ 
2 
3 
________ 
3 
4 
________ 
4 
5 
________ 
5 
6 
________ 
6 
7 
________ 
7 
8 
________ 
8 
9 

, 당신은 첫 번째 요소가 제거지고 최근의 요소가 큐에 추가지고 있음을 분명히 알 수 있습니다.

내 질문 : 좋은 해결책입니까? 아니면 다른 좋은 해결책이 있습니까?

편집 : 자주 삭제의이 시나리오에서는LinkedBlockingQueue보다 ArrayBlockingQueue 낫다?

+1

귀하의 작업에는 컬렉션이 스레드 안전해야한다는 내용이 포함되어 있지 않습니까? 너의 것이 아니기 때문에. 쓰레드는 삽입을 막히게 될 수있다. – zapl

+0

'''queue.size()'''를 호출하는 것은 연결된 목록 유형의 경우 O (N)입니다. 추가 할 때마다이 작업을 수행하므로 링크 된 목록의 이점을 실제로 얻지 못합니다. – Matthew

+0

@Matthew'LinkedBlocking (De) Queue' (그리고이 코드에서 사용되는'ArrayBlockginQueue')의 O (1)은 컬렉션이 수정 될 때마다 크기를 저장하고 업데이트하기 때문입니다. 그것은 실제로 ConcurrentLinkedQueue와 몇몇 다른 것들에 대해서는 O (n)입니다. – zapl

답변

5

휠을 재발 명하지 마십시오. 고정 용량의 LinkedBlockingQueue 만 사용하면 나사산 안전 FIFOBlockingQueue입니다. 더 자세한 내용 here.

if (queue.size() > capacity - 1){ 
    queue.remove();   
} 
queue.put(element); 

을 당신은 synchronized 블록으로 포장 또는 명시 적 Lock를 사용해야합니다 :

코드의 문제는 당신이 그것으로 경쟁 조건 문제를 다음과 같은 작업 원자 등의하지에 직면 할 수 않는 것입니다 그것은 중요한 부분이므로 보호해야하며 여러 스레드가 동시에 호출하는 것을 원하지 않습니다.

BlockingQueue queue = new LinkedBlockingQueue(2); 
for (int i=0; i< 10; i++){ 
    // Try to add the object and return immediately if it is full 
    // then if it could not be added, 
    // remove the last element of the queue and try again 
    while (!queue.offer(i, 0L, TimeUnit.MICROSECONDS)) { 
     queue.remove(); 
    } 
    for (Iterator it = queue.iterator(); it.hasNext();){ 
     System.out.println(it.next()); 
    } 
    System.out.println("________"); 
} 

출력 : : 나는 동시 패키지에서의 BlockingQueue를 사용하지 않을 것을 먼저 인정해야

0 
________ 
0 
1 
________ 
1 
2 
________ 
2 
3 
________ 
3 
4 
________ 
4 
5 
________ 
5 
6 
________ 
6 
7 
________ 
7 
8 
________ 
8 
9 
________ 
+0

이전 요소는 어떻게 삭제 되나요? grepcode insert() 메소드에서 코드를 찾지 못했습니다. –

+0

'LinkedBlockingQueue'의'put' 메소드는 필요한 경우 공간이 사용 가능하게 될 때까지 기다립니다 (블록). 초과 요소는 제거하지 않습니다. –

+0

이 경우 용량을 2로 설정하면 대기열 크기는> 2입니까? –

3

하지만, 여기에

는이 BlockingQueue와 함께 할 수있는 방법입니다 전에 다중 스레드 프로그래밍을 했어. 여기에 문제가있다 생각

:

if (queue.size() > capacity - 1){ 
    queue.remove();   
} 

동시에이 방법을 실행하는 여러 스레드가 있다면, 여러 스레드가이 검사를 할 수있는 그들이 걸릴 전에 그들의 좋은 번호를 true로 평가 할 수 동작. 따라서이 경우 remove()은 예상보다 많은 시간을 호출 할 수 있습니다.

기본적으로 논리를 그대로 유지하려면 크기를 확인한 다음 다른 스레드가 큐의 크기를 변경할 수 없다는 것을 확인해야합니다. 요소 제거와 같은 작업을 수행하십시오.이 문제를 해결하는

한 가지 방법과 같이 동기화 블록으로 래핑 할 수 있습니다 :

synchornized (queue) { 
    if (queue.size() > capacity - 1){ 
    queue.remove();   
    } 
    queue.put(element); 
    for (Iterator it = queue.iterator(); it.hasNext();){ 
    System.out.println(it.next()); 
    } 
    System.out.println("________"); 
} 

이것은 당신이 그것의 현재 크기를 확인 후 queue가 다른 스레드에 의해 액세스되지 않는 것을 보장한다. 동기화 된 항목이 많을수록 다른 스레드가 작업을 수행하기 전에 대기해야하므로 프로그램 속도가 느려질 수 있습니다. 이 키워드에 대한 자세한 내용은 here을 참조하십시오.

+0

흠. 별도의 프로그램에서 두 개의 스레드를 테스트했습니다. 나는 실을 늘릴 것이다. 대안을 제안 할 수 있습니까? –

+0

이것은 단지 2 개의 스레드로 자주 발생하는 것이 아닙니다. 그러나 만약 당신이 그것에 스레드의 톤을 던져 결국 결국 당신은 모순을 볼 수 있습니다. – arjabbar

관련 문제