我有一个webapp,我正在进行一些负载/性能测试,特别是在我们希望有几百个用户访问同一页面并在此页面上每10秒点击一次刷新的功能.我们发现我们可以使用此功能进行改进的一个方面是在一段时间内缓存来自Web服务的响应,因为数据没有变化.
在实现这个基本缓存之后,在一些进一步的测试中,我发现我没有考虑并发线程如何同时访问Cache.我发现在大约100毫秒内,大约有50个线程试图从缓存中获取对象,发现它已经过期,命中Web服务以获取数据,然后将对象放回缓存中.
原始代码看起来像这样:
private SomeData[] getSomeDataByEmail(WebServiceInterface service, String email) {
final String key = "Data-" + email;
SomeData[] data = (SomeData[]) StaticCache.get(key);
if (data == null) {
data = service.getSomeDataForEmail(email);
StaticCache.set(key, data, CACHE_TIME);
}
else {
logger.debug("getSomeDataForEmail: using cached object");
}
return data;
}
Run Code Online (Sandbox Code Playgroud)
因此,为了确保在对象key过期时只有一个线程正在调用Web服务,我认为我需要同步Cache get/set操作,并且似乎使用缓存键是一个很好的候选对象同步(这样,对电子邮件b@b.com的此方法的调用不会被方法调用a@a.com阻止).
我将方法更新为如下所示:
private SomeData[] getSomeDataByEmail(WebServiceInterface service, String email) {
SomeData[] data = null;
final String key = "Data-" + email;
synchronized(key) {
data =(SomeData[]) StaticCache.get(key);
if (data == null) {
data = service.getSomeDataForEmail(email); …Run Code Online (Sandbox Code Playgroud) java multithreading synchronization synchronized thread-safety
在不锁定整个集合的情况下,防止在键值集中并发更新一个记录的最佳方法是什么?从语义上讲,我正在寻找某种键的锁定(理想情况下,Java实现,但不一定):
interface LockByKey {
void lock(String key); // acquire an exclusive lock for a key
void unlock(String key); // release lock for a key
}
Run Code Online (Sandbox Code Playgroud)
此锁用于同步对远程存储的访问,因此某些同步Java集合不是一个选项.
我正在寻找一种基于它接收的参数同步方法的方法,如下所示:
public synchronized void doSomething(name){
//some code
}
Run Code Online (Sandbox Code Playgroud)
我想doSomething基于这样的name参数同步方法:
线程1:doSomething("a");
线程2:doSomething("b");
线程3:doSomething("c");
线程4:doSomething("a");
线程1,线程2和线程3将执行代码而不同步,但线程4将等待,直到线程1完成代码,因为它具有相同的"a"值.
谢谢
UPDATE
根据都铎的解释,我认为我面临另一个问题:这是新代码的示例:
private HashMap locks=new HashMap();
public void doSomething(String name){
locks.put(name,new Object());
synchronized(locks.get(name)) {
// ...
}
locks.remove(name);
}
Run Code Online (Sandbox Code Playgroud)
我没有填充锁定映射的原因是因为name可以有任何值.
基于上面的示例,由于HashMap不是线程安全的,因此在同一时间由多个线程添加/删除散列映射中的值时会出现问题.
所以我的问题是如果我创建了HashMap一个ConcurrentHashMap线程安全的,那么synchronized块会阻止其他线程访问locks.get(name)吗?
我正在尝试设计一个基于密钥的锁定工具:类似于正常的可重入锁定,而不是lock()和unlock(),你锁定(密钥)和解锁(密钥),合同中没有人会如果key.equals(key1),能够同时锁定(key1).
这段代码会起作用吗?是否有更有效的解决方案?我特别不喜欢while循环,同时试图将锁定放在地图中...
package luca;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReentrantLock;
public class KeyedReentrantLock<K> {
private ConcurrentMap<K, ReentrantLock> lockMap = new ConcurrentHashMap<K, ReentrantLock>();
public void lock(K key) {
ReentrantLock oldLock = lockMap.get(key);
if (oldLock != null && oldLock.isHeldByCurrentThread()){
// increase lock count and return.
oldLock.lock();
return;
}
ReentrantLock newLock = new ReentrantLock();
newLock.lock();
while ((oldLock = lockMap.putIfAbsent(key, newLock)) != null){
// wait for the old lock to be released;
oldLock.lock();
oldLock.unlock();
}
return;
}
public void unlock(K key){
ReentrantLock lock = …Run Code Online (Sandbox Code Playgroud) 我想在Java中做这样的事情
public void giveMoney(String userId, int money) {
synchronized (userId) {
Profile p = fetchProfileFromDB(userId);
p.setMoney(p.getMoney() + userId);
saveProfileToDB(p);
}
}
Run Code Online (Sandbox Code Playgroud)
但是,当然,对字符串进行同步是不正确的.做这样的事情的正确方法是什么?
我试图在spring控制器中使用synchronize方法.因为我们的支付网关一次点击方法[@RequestMapping(value ="/ pay",method = RequestMethod.POST)]不同的交易[txn id:txn01&txn02].但由于使用了同步块,这两个不同的事务处理逐个并行处理.
问题 - >为什么我在控制器中使用同步块就是说,事务[txn01]命中[@RequestMapping(value ="/ pay",method = RequestMethod.POST)]两次,就像来自支付网关的重复呼叫一样.在完成第一次呼叫[后端处理]之前,我从支付网关获得相同转账的第二次呼叫.
有没有办法处理两个不同的事务并行使用同步块中的事务ID而不是重复调用我的意思是相同的转义.请指教.
如果我的问题不清楚,请告诉我.
@RequestMapping(value="/pay",method=RequestMethod.POST)
public String payAck(HttpServletRequest httpRequest,HttpServletResponse httpResponse,HttpSession session){
synchronized (this) {
return this.processPayAck(httpRequest, httpResponse, session);
}
}
public synchronized String processPayAck(HttpServletRequest httpRequest,HttpServletResponse httpResponse,HttpSession session){
// Payment Acknowledgment process here
if (sametranIDNotExists) {
// first call here
callWS(); - processing business logic.
return someURL;
} else {
// Gets second call here before first call completed
return someURL;
}
}
Run Code Online (Sandbox Code Playgroud)
修改后的代码
在同步块中使用实习生是否正确?
@RequestMapping(value="/pay",method=RequestMethod.POST)
public String payAck(HttpServletRequest httpRequest,HttpServletResponse …Run Code Online (Sandbox Code Playgroud) 我经常想要访问(并且可能添加/删除)给定的元素ConcurrentMap,以便一次只有一个线程可以访问任何单个键。做这个的最好方式是什么?同步密钥本身不起作用:其他线程可能通过equal实例访问同一密钥。
如果答案仅适用于guava MapMaker构建的地图就足够了。
在Java中,字符串很特殊.
由于具有相同内容的字符串文字在公共池中共享存储,因此Java的String被设计为不可变的.也就是说,一旦构造了String,就无法修改其内容.否则,共享相同存储位置的其他String引用将受到更改的影响,这可能是不可预测的,因此是不合需要的.
如果我在String上同步怎么办?我会锁定共享相同内容的String的所有实例吗?
例如:我有一个多线程类,可以从数据文件中读取和写入.每天有1个文件,我想同步读取和写入同一个文件,以防止不可预测的行为.我可以简单地同步文件名(String)吗?
我有一个方法,通过3个并发线程在对象实例上调用.我感兴趣的锁是基于价值而不是对象.例如,如果两个线程(T1,T2)正在处理RecordID = 123并且T3正在处理RecordID = 456.该方法应仅锁定T2,T3应继续执行.
目前,我正在使用Lock,但如果T1被锁定,它将锁定T2和T3.
public void doSomething(String id){
try {
lock.lock();
MyRecord r = find(id);
...
....
} finally{
lock.unlock();
}
}
Run Code Online (Sandbox Code Playgroud) java ×9
synchronized ×4
locking ×3
algorithm ×1
concurrency ×1
guava ×1
spring-mvc ×1
string ×1