MySQL有一个方便的功能:
SELECT GET_LOCK("SomeName")
Run Code Online (Sandbox Code Playgroud)
这可用于为应用程序创建简单但非常具体的基于名称的锁.但是,它需要数据库连接.
我有很多情况,比如:
someMethod() {
// do stuff to user A for their data for feature X
}
Run Code Online (Sandbox Code Playgroud)
它没有意义的只是同步的这种方法,因为,例如,如果调用此方法对于在此期间用户B,用户B不需要等待用户A完成它开始之前,用户只能操作A和功能X组合需要等待.
使用MySql锁我可以做类似的事情:
someMethod() {
executeQuery("SELECT GET_LOCK('userA-featureX')")
// only locked for user A for their data for feature X
executeQuery("SELECT RELEASE_LOCK('userA-featureX')")
}
Run Code Online (Sandbox Code Playgroud)
由于Java锁定是基于对象的,因此我似乎需要创建一个新对象来表示此锁的情况,然后将其放在某个地方的静态缓存中,以便所有线程都可以看到它.锁定该情况的后续请求然后将锁定对象定位在高速缓存中并获取其锁定.我试图创建这样的东西,但锁缓存本身需要同步.此外,很难检测何时不再使用锁定对象,以便可以从缓存中删除锁定对象.
我查看了Java并发软件包,但没有什么能够处理这样的事情.有没有一种简单的方法来实现这一点,还是我从错误的角度看待这个?
编辑:
为了澄清,我不打算提前创建一个预定义的锁池,我想按需创建它们.我想的一些伪代码是:
LockManager.acquireLock(String name) {
Lock lock;
synchronized (map) {
lock = map.get(name);
// doesn't exist yet - create and store
if(lock == null) {
lock = new Lock();
map.put(name, lock);
}
}
lock.lock();
}
LockManager.releaseLock(String name) …Run Code Online (Sandbox Code Playgroud) 在不锁定整个集合的情况下,防止在键值集中并发更新一个记录的最佳方法是什么?从语义上讲,我正在寻找某种键的锁定(理想情况下,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集合不是一个选项.
我知道
同步代码块时,指定要将哪个对象的锁用作锁,因此您可以使用某些第三方对象作为此代码段的锁.这使您能够在单个对象中拥有多个用于代码同步的锁.
但是,我不明白需要将参数传递给块.因为我是否传递String的实例并不重要,所以作为同步块的一些随机类的实例作为同步块的工作完全无论传递给块的参数如何.
所以我的问题是,如果无论如何同步块阻止两个线程同时进入临界区.那么为什么需要传递一个论点呢?(我的意思是默认获取某些随机对象的锁定).
我希望我正确地提出了我的问题.
我尝试了以下示例,随机参数是同步块.
public class Launcher {
public static void main(String[] args) {
AccountOperations accOps=new AccountOperations();
Thread lucy=new Thread(accOps,"Lucy");
Thread sam=new Thread(accOps,"Sam");
lucy.start();
sam.start();
}
}
Run Code Online (Sandbox Code Playgroud)
使用非静态同步块:
public class AccountOperations implements Runnable{
private Account account = new Account();
public void run(){
for(int i=0;i<5;i++){
makeWithdrawal(10);
}
}
public void makeWithdrawal(int amount){
String str="asd"
synchronized (str /* pass any non-null object the synchronized block works*/) {
if(account.getAmount()>10){
try{
Thread.sleep(5000);
}catch(InterruptedException e){
e.printStackTrace();
}
account.withdraw(amount);
System.out.println(Thread.currentThread().getName()+" has withdrawn 10, …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)
但是,当然,对字符串进行同步是不正确的.做这样的事情的正确方法是什么?
我用户sun jdk 1.5 ThreadPoolExecutor(24,24,60,TimeUnit.SECONDS,new LinkedBlockingQueue()).soemtime我使用jdb工具查找线程池中所有线程的状态是"在监视器中等待",代码是:
String key = getKey(dt.getPrefix(), id);
synchronized (key.intern()) { ----->
Run Code Online (Sandbox Code Playgroud)
"synchronized(key.intern())"中有问题吗?
我使用jdb工具获取以下信息,24个线程的状态是"在监视器中等待",这意味着24个线程在"key.intern()"处于死锁状态.
(java.lang.Thread)0x28 pool-3-thread-2在监视器中等待
(java.lang.Thread)0x27 pool-3-thread-3在监视器中等待
(java.lang.Thread)0x1b pool-3-thread-4在监视器中等待
(java.lang.Thread)0x1a pool-3-thread-5在监视器中等待
(java.lang.Thread)0x19 pool-3-thread-6在监视器中等待
(java.lang.Thread)0x18 pool-3-thread-7在监视器中等待
(java.lang.Thread)0x17 pool-3-thread-8在监视器中等待...
所以结果是:在多线程环境中,Sting intern()方法可能会死锁,好吗?
在探索了java的字符串内部结构后,我对所谓的"烫发空间"感到困惑.我最初的理解是它保留了String 文字以及类元数据,如本问题所述.
我还阅读了有关该String.intern()方法的内容,并将其String放入String Pool中,返回对它的唯一实例的引用.我的理解是,这是与JVM的perm空间中存在的字符串文字相同的字符串池.对我来说,"烫发空间"可以修改是不可能的(毕竟它是永久性的,是吗?).但后来我发现这个问题,EJP对接受的答案的最高投票评论解释了这一点
现在,实习生的字符串已经可以用GC了.
暗示GC在perm空间上运行,这似乎不是永久性的.这如何调和?GC是否检查了烫发空间中的所有内容?GC是否检查字符串池中的所有内容,包括源中的字符串文字?内联字符串是否有第二个字符串池?GC是否只知道在收集时查看实习生的字符串?或者这个评论是错误的并且实际上是一个字符串阻止它成为GC'd(我希望不是这种情况)?
假设我有一个为Web应用程序创建新用户的方法.该方法本身调用一个静态助手类,该类创建一个SQL语句,用于执行实际插入到我的数据库中.
public void createUserInDb(String userName){
SQLHelper.insertUser(userName);
}
Run Code Online (Sandbox Code Playgroud)
我希望同步此方法,以便如果传入的参数(userName)在这些线程上相同,则不能由不同的线程同时调用它.我知道我可以使用synchronized关键字同步方法执行,但这会阻止不同的线程同时执行该方法.如果传入的变量相同,我只想防止并发执行.Java中有一个简单的构造可以让我这样做吗?
我试图在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) 我写一些这样的代码:
public static void function7() {
String str = "123";
String str2 = "123";
synchronized (str) {
if(str != null) {
str2 = "123";
}else{
str = "456";
}
System.out.println(str2);
}
}
Run Code Online (Sandbox Code Playgroud)
代码编译良好。但是Eclipse的一个插件,查找错误,给出以下错误报告:
常量字符串在JVM加载的所有其他类中进行实习和共享。因此,这可能会锁定其他代码可能也会锁定的内容。这可能会导致非常奇怪且难以诊断的阻塞和死锁行为。
到底是什么意思?
使用静态变量进行同步有什么影响?
public class Something {
public static final String LOCK = "lala";
public void doSomething(){
synchronized(LOCK){
...
}
}
}
Run Code Online (Sandbox Code Playgroud) 基本上,我有一个包含 2 个方法的类:一个将对象序列化为 XML 文件,另一个从 XML 读取对象。以下是恢复对象的方法中同步部分的示例:
public T restore(String from) throws Exception {
// variables declaration
synchronized (from) {
try {
decoder = new XMLDecoder(new BufferedInputStream(
new FileInputStream(from)));
restoredItem = decoder.readObject();
decoder.close();
} catch (Exception e) {
logger.warning("file not found or smth: " + from);
throw new Exception(e);
}
}
// try to cast it
}
Run Code Online (Sandbox Code Playgroud)
序列化对象时采用类似的方法。现在,当我创建一个单元测试时,它依次创建 10 个线程,每个线程尝试序列化并立即读取布尔值或字符串,它会失败,显示发生 ClassCastExceptions。这让我觉得我的序列化是错误的(在单线程环境中一切正常)。如果你一直和我在一起:),这里有两个我需要你帮助的问题:
2个问题:
class A implements Runnable {
String str = "hello"; // line 2.
public void run(){
Synchronized(str){
System.out.println(str+" "+Thread.currentThread().getName());
Thread.sleep(100);
System.out.println(str+" "+Thread.currentThread().getName());
//anything
}
}
public void static main(String[] args){
Thread one = new Thread(new A(),"one").start();
Thread two = new Thread(new A(),"two").start();
}
}
Run Code Online (Sandbox Code Playgroud) java ×12
synchronized ×4
string ×3
concurrency ×2
deadlock ×2
locking ×2
algorithm ×1
io ×1
jvm ×1
spring-mvc ×1