我要求在多线程环境中拥有一个消息队列缓存,每秒会有数千个请求到来。
如果队列不为空,则每个请求线程都应弹出队列中的消息(并且不应该传递重复消息)+减少db中的计数器。如果队列为空,则线程将获取固定数量的消息(例如100)来自DB并填充队列缓存(其他线程应该在队列填充时等待)然后弹出一条消息+递减db中的计数器并返回。
db中的弹出和递减计数器应该同步以避免任何不一致。
因此,从要求可以看出,缓存将具有更多的读取和删除(弹出)操作,但是更少的写入操作(仅当缓存为空时)。
现在我有一个同步方法getMessage,里面有一个ArrayList,我在这个方法中做了上面的操作(如果是空的,则弹出输出,然后弹出)但我显然面临很多争用问题。
如果在读取/删除时,并发线程获得不同的锁,并且在写入时,锁应该在整个缓存上,那么这将减少我的争用问题。
在这种情况下哪个java缓存最好?在负载中,由于这个原因我面临着低性能。请给我一些更好的主意。
答案 0 :(得分:4)
而不是Synchronize
,您可以查看ReentrantLocks
。根据您的要求,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();
}
}
}
}