Web服务中的Java同步

时间:2015-05-05 06:36:12

标签: java multithreading web-services concurrency synchronization

我有一个托管在tomcat上的java restful webservice程序。在我的一个Web服务方法中,我从redis加载一个大型对象(大约25,000个条目)的arraylist。这个arraylist每30分钟更新一次。从这个arraylist一直有多个线程读取。当我更新arraylist时,我希望最小化中断/延迟,因为可能有其他线程从中读取。

我想知道最好的方法是什么?一种方法是使用synchronized关键字来更新列表的方法。但是,synchronized方法有一个开销,因为在更新进行时没有线程可以读取。更新方法本身可能需要几百毫秒,因为它涉及读取redis +反序列化。

class WebService {

 ArrayList<Entry> list = new ArrayList<Entry>();

    //need to call this every 30 mins.
    void syncrhonized updateArrayList(){
      //read from redis & add elements to list
    }

    void readFromList(){
      for(Entry e: list) {
       //do some processing
      }
    }

}

更新了最终解决方案: 我最终没有使用显式同步原语。

4 个答案:

答案 0 :(得分:3)

是否必须更新相同的List实例?您可以每30分钟构建一个新列表并替换volatile引用吗?

这些方面的东西:

class WebService {
    private volatile List<Entry> theList;

    void updateList() {
        List<Entry> newList = getEntriesFromRedis();
        theList = Collections.unmodifiableList(newList);
    }

    public List<Entry> getList() {
        return theList;
    }
}

这种方法的优点是您不必在其他任何地方进行任何其他同步。

答案 1 :(得分:1)

您需要一个读写器锁(或Java中的ReadWriteLock)。

读写器锁将允许读取操作的并发访问,但允许写入的互斥访问。

看起来像

class WebService {
    final ReentrantReadWriteLock listRwLock = new ReentrantReadWriteLock();
    ArrayList<Entry> list = new ArrayList<Entry>();

    //need to call this every 30 mins.
    void updateArrayList(){
        listRwLock.writeLock().lock();
        try {
            //read from redis & add elements to list
        } finally {
            listRwLock.writeLock().unlock()
        }
    }

    void readFromList(){
        listRwLock.readLock().lock();
        try {
            for(Entry e: list) {
                //do some processing
            }
        } finally {
            listRwLock.readLock().unlock()
        }

    }

}

答案 2 :(得分:0)

这是我最终得到的解决方案,

class WebService {

 // key = timeWindow (for ex:10:00 or 10:30 or 11:00), value = <List of entries for that timewindow>
 ConcurrentHashMap<String, List<Entry>> map= new ConcurrentHashMap<String, List<Entry>>();

    //have setup a timer to call this every 10 mins.
    void updateArrayList(){
     // populate the map for the next time window with the corresponding entries. So that its ready before we start using it. Also, clean up the expired entries for older time windows.

    }

    void readFromList(){
      list = map.get(currentTimeWindow)
      for(Entry e: list) {
       //do some processing
      }
    }

} 

答案 3 :(得分:-1)

ArrayList不是线程安全的。您必须使用向量列表使其线程安全。

你也可以使用Collections Api来使用Thread safe Array列表,但我会推荐vector list,因为它已经为你提供了你想要的东西。

 //Use Collecions.synzhonizedList method
 List list = Collections.synchronizedList(new ArrayList());
 ...

 //If you wanna use iterator on the synchronized list, use it
 //like this. It should be in synchronized block.
 synchronized (list) {
   Iterator iterator = list.iterator();
   while (iterator.hasNext())
   ...
  iterator.next();
  ...
}

我建议你通过这个: http://beginnersbook.com/2013/12/difference-between-arraylist-and-vector-in-java/