Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.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/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
在java中,在并发环境中使用的最佳队列缓存是什么_Java_Multithreading_Caching_Concurrency - Fatal编程技术网

在java中,在并发环境中使用的最佳队列缓存是什么

在java中,在并发环境中使用的最佳队列缓存是什么,java,multithreading,caching,concurrency,Java,Multithreading,Caching,Concurrency,我需要在多线程环境中具有消息队列缓存,在多线程环境中,每秒有数千个请求 如果队列不为空,则每个请求线程应从队列中弹出消息(并且任何线程都不应获取重复消息),并在db中递减一个计数器。如果队列为空,则线程将从db中提取固定数量的消息(例如100)并填充队列缓存(其他线程应在队列填充时等待)然后弹出一条消息+以db为单位递减一个计数器并返回 db中的弹出和递减计数器应同步,以避免任何不一致 因此,从需求来看,很明显,缓存将有更多的读和删除(弹出)操作,而写操作更少(仅当缓存为空时) 现在我有一个同步

我需要在多线程环境中具有消息队列缓存,在多线程环境中,每秒有数千个请求

如果队列不为空,则每个请求线程应从队列中弹出消息(并且任何线程都不应获取重复消息),并在db中递减一个计数器。如果队列为空,则线程将从db中提取固定数量的消息(例如100)并填充队列缓存(其他线程应在队列填充时等待)然后弹出一条消息+以db为单位递减一个计数器并返回

db中的弹出和递减计数器应同步,以避免任何不一致

因此,从需求来看,很明显,缓存将有更多的读和删除(弹出)操作,而写操作更少(仅当缓存为空时)

现在我有一个同步的方法getMessage,其中有一个ArrayList,我在这个方法中执行上面的操作(如果为空,则弹出,否则取出,然后弹出),但是我显然面临很多争用问题

如果在读取/删除时,并发线程获得不同的锁,并且在写入时,锁应该位于整个缓存上,那么这将减少我的争用问题


在这种情况下,哪种java缓存应该是最好的?由于这个原因,在负载中我面临低性能。请给我一些更好的主意

而不是
同步
您可以查看
可重入锁
。对于您的需求,Java中有一个
ReentrantReadWriteLock
类。有关详细信息,您可以参考Java文档。基本上,在读线程访问数据的次数多于写线程访问数据的情况下,建议使用
ReentrantReadWriteLock

根据这个实现,多个线程可以读取相同的资源而无需锁定。但是对资源的一次写入操作将锁定它,并且不允许同时进行其他读取或写入操作

在线提供了许多示例,您可以参考实现
ReentrantReadWriteLock

样本:

package concurrency.reentrantreadwrite;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReentrantReadWrite {
    public static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
    public static StringBuffer message = new StringBuffer("a");

    public static void main(String[] args) throws InterruptedException{
    Thread t1 = new Thread(new Reader(lock, message));
    Thread t2 = new Thread(new WriterA(lock, message));
    Thread t3 = new Thread(new WriterB(lock, message));
    t1.start();
    t2.start();
    t3.start();
    t1.join();
    t2.join();
    t3.join();
    }
}


package concurrency.reentrantreadwrite;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Reader implements Runnable 
{
    ReentrantReadWriteLock lock = null;
    StringBuffer message = null;

    public Reader(ReentrantReadWriteLock lock, StringBuffer message) {
    this.lock = lock;
    this.message = message;
    }

    public void run() 
    {
    for(int i = 0; i<= 10; i ++) 
    {
        if(lock.isWriteLocked()) {
        System.out.println("I'll take the lock from Write");
        }
        lock.readLock().lock();
        System.out.println("ReadThread " + Thread.currentThread().getId() + " ---> Message is " + message.toString() );
        lock.readLock().unlock();
    }
    }
}


package concurrency.reentrantreadwrite;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class WriterA implements Runnable 
{
    ReentrantReadWriteLock lock = null;
    StringBuffer message = null;

    public WriterA(ReentrantReadWriteLock lock, StringBuffer message) {
    this.lock = lock;
    this.message = message;
    }

    public void run() 
    {
    for(int i = 0; i<= 10; i ++) 
    {
        try {
        lock.writeLock().lock();
        message.append("a");
        }finally {
        lock.writeLock().unlock();
        }
    }
    }
}

package concurrency.reentrantreadwrite;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class WriterB implements Runnable 
{
    ReentrantReadWriteLock lock = null;
    StringBuffer message = null;

    public WriterB(ReentrantReadWriteLock lock, StringBuffer message) {
    this.lock = lock;
    this.message = message;
    }

    public void run() 
    {
    for(int i = 0; i<= 10; i ++) 
    {
        try {
        lock.writeLock().lock();
        message.append("b");
        }finally {
        lock.writeLock().unlock();
        }
    }
    }
}
package concurrency.reentrantreadwrite;
导入java.util.concurrent.locks.ReentrantReadWriteLock;
公共类可重入写入{
public static ReentrantReadWriteLock lock=新的ReentrantReadWriteLock(true);
公共静态StringBuffer消息=新StringBuffer(“a”);
公共静态void main(字符串[]args)引发InterruptedException{
线程t1=新线程(新读卡器(锁、消息));
线程t2=新线程(新写线程(锁、消息));
线程t3=新线程(新WriterB(锁,消息));
t1.start();
t2.start();
t3.start();
t1.join();
t2.连接();
t3.join();
}
}
包并发性.reentrantreadwrite;
导入java.util.concurrent.locks.ReentrantReadWriteLock;
公共类读取器实现可运行
{
REENTRANDREADWRITELOCK lock=null;
StringBuffer消息=null;
公共读取器(可重传写锁,StringBuffer消息){
this.lock=锁;
this.message=消息;
}
公开募捐
{

对于(int i=0;i而不是
Synchronize
您可以查看
reentrantlock
。根据您的需求,Java中有一个
reentrandredwritelock
类。您可以参考Java文档了解详细信息。基本上,如果数据被比w更多的读卡器线程访问,建议使用
reentrandredwritelock
里特线

根据这个实现,多个线程可以读取同一个资源而无需锁定。但是对该资源的单个写入操作将锁定该资源,并且不允许同时执行其他读取或写入操作

在线提供了许多示例,您可以参考实现
ReentrantReadWriteLock

样本:

package concurrency.reentrantreadwrite;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReentrantReadWrite {
    public static ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
    public static StringBuffer message = new StringBuffer("a");

    public static void main(String[] args) throws InterruptedException{
    Thread t1 = new Thread(new Reader(lock, message));
    Thread t2 = new Thread(new WriterA(lock, message));
    Thread t3 = new Thread(new WriterB(lock, message));
    t1.start();
    t2.start();
    t3.start();
    t1.join();
    t2.join();
    t3.join();
    }
}


package concurrency.reentrantreadwrite;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Reader implements Runnable 
{
    ReentrantReadWriteLock lock = null;
    StringBuffer message = null;

    public Reader(ReentrantReadWriteLock lock, StringBuffer message) {
    this.lock = lock;
    this.message = message;
    }

    public void run() 
    {
    for(int i = 0; i<= 10; i ++) 
    {
        if(lock.isWriteLocked()) {
        System.out.println("I'll take the lock from Write");
        }
        lock.readLock().lock();
        System.out.println("ReadThread " + Thread.currentThread().getId() + " ---> Message is " + message.toString() );
        lock.readLock().unlock();
    }
    }
}


package concurrency.reentrantreadwrite;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class WriterA implements Runnable 
{
    ReentrantReadWriteLock lock = null;
    StringBuffer message = null;

    public WriterA(ReentrantReadWriteLock lock, StringBuffer message) {
    this.lock = lock;
    this.message = message;
    }

    public void run() 
    {
    for(int i = 0; i<= 10; i ++) 
    {
        try {
        lock.writeLock().lock();
        message.append("a");
        }finally {
        lock.writeLock().unlock();
        }
    }
    }
}

package concurrency.reentrantreadwrite;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class WriterB implements Runnable 
{
    ReentrantReadWriteLock lock = null;
    StringBuffer message = null;

    public WriterB(ReentrantReadWriteLock lock, StringBuffer message) {
    this.lock = lock;
    this.message = message;
    }

    public void run() 
    {
    for(int i = 0; i<= 10; i ++) 
    {
        try {
        lock.writeLock().lock();
        message.append("b");
        }finally {
        lock.writeLock().unlock();
        }
    }
    }
}
package concurrency.reentrantreadwrite;
导入java.util.concurrent.locks.ReentrantReadWriteLock;
公共类可重入写入{
public static ReentrantReadWriteLock lock=新的ReentrantReadWriteLock(true);
公共静态StringBuffer消息=新StringBuffer(“a”);
公共静态void main(字符串[]args)引发InterruptedException{
线程t1=新线程(新读卡器(锁、消息));
线程t2=新线程(新写线程(锁、消息));
线程t3=新线程(新WriterB(锁,消息));
t1.start();
t2.start();
t3.start();
t1.join();
t2.连接();
t3.join();
}
}
包并发性.reentrantreadwrite;
导入java.util.concurrent.locks.ReentrantReadWriteLock;
公共类读取器实现可运行
{
REENTRANDREADWRITELOCK lock=null;
StringBuffer消息=null;
公共读取器(可重传写锁,StringBuffer消息){
this.lock=锁;
this.message=消息;
}
公开募捐
{
对于(int i=0;i摘要
当你面对一个架构问题时,你应该提取一个“模型”并抽象出任何带有接口的外部部件/系统。因此,你可以很容易地从让这些接口等待一个固定的时间开始,然后是随机的,接下来是采样的持续时间等等

它使你更清楚你的算法/系统是如何工作的,并使重构/调整变得非常容易,直到“模型”令人满意。随着你的模型变得更清晰,它也使你更容易插入监视并显示你必须监视的内容/位置。如果需要,我可以添加更完整的解释

从您的问题来看,您应该在“缓存消耗”和“缓存生成”之间添加更好的分离。您还必须使用非阻塞算法并更平滑地推送到“缓存”。请注意,“非阻塞”这并不意味着你的线程永远不会饿死;如果没有什么可处理的,它们就必须处于休眠状态。但是,它们不应该互相阻塞

外部系统 正如总结中提到的,必须抽象外部系统,并且必须使用默认值/花费的时间。因此,您可以使用相同的场景/模型,但不能使用changi
class Model<T>  {
  private Storage<T>  storage;
  private int         fetchSize;
  private Consumer<T> processor;

  /**
   * while active:
   *    Try to poll a message from cache
   *    if none:
   *      Fetch from storage
   *      Put fetched messages to cache
   *    else:
   *      Process message
   *      Update storage according to processed message
   **/
  public void consume(BooleanSupplier active) {
    try {
      while (active.getAsBoolean()) {
        T message = cache.poll();
        if (message == null) {
          // Fetch new messages from storage
          List<T> newMessages = new ArrayList<>(fetchSize);
          synchronized (storage) {
            storage.drainTo(newMessages, fetchSize);
          }
          // Push new messages to cache
          for (T newMessage : newMessages) {
            cache.put(newMessage);
          }
        } else {
          processor.accept(message);
          storage.update(message);
        }
      }
    } catch (InterruptedException e) {
      if (!active.getAsBoolean()) {
        throw new RuntimeException(e);
      }
    }
  }
}
class ImprovedModel<T>  {
  private Storage<T>  storage;
  private int         fetchSize;
  private Consumer<T> processor;
  private StampedLock lock = new StampedLock();

  /**
   * while active:
   *    Try to poll a message from cache
   *    if none:
   *      if storage available:
   *        Transfer from storage to cache
   *      else:
   *        Take message from cache
   *    if message:
   *      Process message
   *      Update storage according to processed message
   **/
  public void consume(BooleanSupplier active) {
    try {
      while (active.getAsBoolean()) {
        T message = cache.poll();
        if (message == null) {
          // Check storage availability
          int stamp = lock.tryWriteLock();
          try {
            if (stamp != 0) {
              storage.drainTo(cache, fetchSize);
            } else {
              message = cache.take();
            }
          } finally {
            lock.unlockWrite(stamp);
          }
        }
        if (message != null) {
          processor.accept(message);
          storage.update(message);
        }
      }
    } catch (InterruptedException e) {
      if (!active.getAsBoolean()) {
        throw new RuntimeException(e);
      }
    }
  }
}