2013-07-25 2 views
1

Мое приложение должно поддерживать журнал запросов на определенный ресурс, а несколько потоков будут записывать записи журнала. Единственная соответствующая информация - это метка времени запроса, и полученная статистика будет равна количеству запросов за последние X секунд. Метод, который возвращает статистику за определенное количество секунд, также должен поддерживать несколько потоков.Безопасность потока при многопоточном доступе к LinkedList

Я думал о приближении обработки параллелизма с использованием рамки Locks, с которой я не самый знакомый, следовательно, этот вопрос. Вот мой код:

import java.util.LinkedList; 
import java.util.concurrent.locks.ReentrantLock; 

public class ConcurrentRecordStats 
{ 
    private LinkedList<Long> recLog; 
    private final ReentrantLock lock = new ReentrantLock(); 

    public LinkedConcurrentStats() 
    { 
     this.recLog = new LinkedList<Long>(); 
    } 

    //this method will be utilized by multiple clients concurrently 
    public void addRecord(int wrkrID) 
    { 
     long crntTS = System.currentTimeMillis(); 
     this.lock.lock(); 
     this.recLog.addFirst(crntTS); 
     this.lock.unlock(); 
    } 

    //this method will be utilized by multiple clients concurrently 
    public int getTrailingStats(int lastSecs) 
    { 
     long endTS = System.currentTimeMillis(); 
     long bgnTS = endTS - (lastSecs * 1000); 

     int rslt = 0; 

     //acquire the lock only until we have read 
     //the first (latest) element in the list 
     this.lock.lock(); 

     for(long crntRec : this.recLog) 
     { 
      //release the lock upon fetching the first element in the list 
      if(this.lock.isLocked()) 
      { 
       this.lock.unlock(); 
      } 

      if(crntRec > bgnTS) 
      { 
       rslt++; 
      } 
      else 
      { 
       break; 
      } 
     } 

     return rslt; 
    } 
} 

Мои вопросы:

  1. Будет ли это использование ReentrantLock обеспечить безопасность потоков?
  2. Нужно ли использовать замок в getTrailingStats?
  3. Могу ли я все это использовать с помощью synchronized блоков? Причина, по которой я пошел с замками, состоит в том, что я хотел иметь такую ​​же блокировку в разделах R и W, чтобы как запись, так и чтение первого элемента в списке (последняя добавленная запись) выполнялись за один поток за раз, а я не мог сделать этого только с synchronized.
  4. Вместо этого следует использовать ReentrantReadWriteLock?
+0

Просто знать, почему вы просто не используете public 'List Collections.synchronizedList (Список )), чтобы получить список, защищенный потоком? – Jack

+0

ли это устранит необходимость в замках? – amphibient

+1

Java.util.concurrent.ConcurrentLinkedDeque является потокобезопасным со слабо согласованным итератором. – assylias

ответ

3

Замки могут представлять собой узкое место в производительности. Альтернативой является использование a ConcurrentLinkedDeque: используйте offerFirst, чтобы добавить новый элемент, и используйте (слабо согласованный) iterator (который не будет бросать ConcurrentModificationException) вместо вашего цикла for-each. Преимущество состоит в том, что это будет работать намного лучше, чем ваша реализация, или реализация synchronizedList, но недостатком является то, что итератор слабо согласован - thread1 может добавлять элементы в список, пока thread2 выполняет итерацию через него, а это означает, что thread2 не будет посчитайте эти новые элементы. Тем не менее, это функционально эквивалентно тому, что thread2 блокирует список, так что thread1 не может его добавить - в любом случае thread2 не считает новые элементы.

+0

, если T2 добавляет элемент, в то время как T1 выполняет итерацию через него, что не является проблемой, потому что T1 не считает новые элементы – amphibient

+0

, но также, мой LinkedList не будет вызывать «ConcurrentModificationException», потому что я повторяю только через ранее введенные элементы – amphibient

+0

IOW , блокировка в 'getTrailingStats' заботится о том, чтобы не вставлять новые элементы, пока читается первый существующий элемент. – amphibient