Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
web服务中的Java同步_Java_Multithreading_Web Services_Concurrency_Synchronization - Fatal编程技术网

web服务中的Java同步

web服务中的Java同步,java,multithreading,web-services,concurrency,synchronization,Java,Multithreading,Web Services,Concurrency,Synchronization,我有一个java restful Web服务程序,它托管在tomcat上。在我的一个web服务方法中,我从redis加载了一个大的arraylist对象(大约25000个条目)。此arraylist每30分钟更新一次。有多个线程一直在读取此arraylist。当我更新arraylist时,我希望造成最小的中断/延迟,因为可能有其他线程从中读取 我想知道做这件事最好的方法是什么?一种方法是对更新列表的方法使用synchronized关键字。但是,同步方法有一个开销,因为在更新过程中没有线程可以读取

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

我想知道做这件事最好的方法是什么?一种方法是对更新列表的方法使用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
      }
    }

}
类Web服务{
ArrayList=新建ArrayList();
//需要每30分钟打一次电话。
void syncrhonized updateArrayList(){
//从redis读取并将元素添加到列表
}
void readFromList(){
对于(条目e:列表){
//做一些处理
}
}
}

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

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

您还可以通过使用Collections Api使用线程安全数组列表,但我建议使用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();
  ...
}
我建议您通过以下方式:

更新的实例必须是相同的
列表吗?您能否每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;
    }
}
类Web服务{
私有易变列表;
void updateList(){
List newList=getEntriesFromRedis();
theList=集合。不可修改列表(newList);
}
公共列表getList(){
返回列表;
}
}
这种方法的优点是,您不必在其他任何地方进行任何其他同步

您需要读写器锁(或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()
        }

    }

}
类Web服务{
final ReentrantReadWriteLock listRwLock=新的ReentrantReadWriteLock();
ArrayList=新建ArrayList();
//需要每30分钟打一次电话。
void updateArrayList(){
listRwLock.writeLock().lock();
试一试{
//从redis读取并将元素添加到列表
}最后{
listRwLock.writeLock().unlock()
}
}
void readFromList(){
listRwLock.readLock().lock();
试一试{
对于(条目e:列表){
//做一些处理
}
}最后{
listRwLock.readLock().unlock()
}
}
}

这是我最终得出的解决方案

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
      }
    }

} 
类Web服务{
//键=时间窗口(例如:10:00或10:30或11:00),值=
ConcurrentHashMap=新的ConcurrentHashMap();
//设置一个计时器,每10分钟调用一次。
void updateArrayList(){
//用相应的条目填充下一个时间窗口的映射。这样在我们开始使用它之前,它就准备好了。另外,清除旧时间窗口的过期条目。
}
void readFromList(){
list=map.get(currentTimeWindow)
对于(条目e:列表){
//做一些处理
}
}
} 

可能有帮助吗?@Seelenvirtuose-我认为
CopyOnWriteArrayList
在这里效率很低,因为30分钟只更新一次<代码>同步块
是一种方法。@最重要的是,你是对的。只是想提供一个替代方案。OP必须选择最适合的。这是ReadWriteLock的一个非常典型的用例。请参考我的回答在上述情况下,它看起来像列表是同步的阅读也。。。这不会让我的阅读速度变慢吗?因为每个线程都必须获得一个锁才能读取?我希望我的读取同时发生,因为列表在大多数情况下保持不变。@plspl-否。不要使用同步数据结构。列表很好(尽管我会编写接口代码,而不是实现..无论如何)。我宁愿在
readFromList()
updateArrayList()
的关键部分进行同步。逃逸分析将导致锁省略。因此,JIT/JVM通常会删除不必要的同步。虽然我怀疑这件事是否会发生在你身上这就是我在想的+1.完全删除同步,但要确保在之前发生同步。使列表
不可修改
可提高性能。。但是在更新发生时应该阻止读取。否则,将出现内存不一致。假设线程1正在处理旧列表中的值。。然后更新被另一个线程调用。线程1仍将处理上一个列表中的值。如果新列表中不存在该值怎么办?。我认为应该完成所有读取,然后才开始更新。假设列表没有试图与自身之外的任何内容保持一致,那么使用列表的旧版本完成已经在进行的请求可能完全没有问题。在不知道OPs要求的情况下无法确定。是的。。如果不存在一些不一致的问题,那么此解决方案将比使用
CopyOnWriteArrayList
或`同步机制'更好。问题的最大可能来源是OP没有讲述整个故事,除了此
列表
,其他一些数据也从redis加载到其他一些结构中。在这种情况下,同一个客户端可以观察一个结构的旧副本和另一个结构的新副本