Java synchronized(){}的异步(非阻塞)版本
有没有一种很好的方法来实现synchronized关键字的异步版本?显然,synchronized()关键字经常会阻塞当前线程。例如:Java synchronized(){}的异步(非阻塞)版本,java,akka,vert.x,Java,Akka,Vert.x,有没有一种很好的方法来实现synchronized关键字的异步版本?显然,synchronized()关键字经常会阻塞当前线程。例如: public static boolean getLockSync(Runnable r) { if (isLocked) { r.run(); return true; } synchronized (My.lock) { // this is blocking, could block for more
public static boolean getLockSync(Runnable r) {
if (isLocked) {
r.run();
return true;
}
synchronized (My.lock) { // this is blocking, could block for more than 1-2 ms
isLocked = true;
r.run();
isLocked = false;
return false;
}
}
我可以从这个块返回一个布尔值-它是同步的。是否有一种异步执行此操作的方法
大概是这样的:
public static void getLockAsync(Runnable r) {
if (isLocked) {
CompletableFuture.runAsync(r);
return;
}
Object.onLockAcquisition(My.lock, () -> { // this is non-blocking
isLocked = true;
r.run();
isLocked = false;
Object.releaseLock(My.lock);
});
}
我创建了Object.onLockAcquisition方法,但正在寻找类似的方法。Vertx中的一个解决方案是工具包的异步锁定调用: 这看起来像:
sd.getLock("mylock", res -> {
Lock lock = res.result();
vertx.setTimer(5000, tid -> lock.release());
});
然而,这并不是我真正想要的解决方案,因为这是一个网络锁,这意味着它比普通内存锁要慢得多。我只需要在单个线程中创建锁,而不是跨线程或进程创建锁。您研究过其他方法吗?根据您试图实现的目标,以下一种或多种方法可能会有所帮助(或无效):
- 双重锁定替代方案(使用volatile+监视器并检查volatile两次,一次锁定前,一次锁定后)
- 使用AtomicXXX,其中有compareAndSet/compareAndExchange等。。方法
- 使用java.util.concurrent.locks
- 使用单线程执行器执行关键部分
- 使用队列
- 对于Vert.x而言,正确的解决方案是使用
SharedData.getLock()
原因是异步性是特定库的一部分,而不是JVM平台的一部分 除非Vert.x以集群模式运行,否则它将返回到本地锁:
public void getLockWithTimeout(String name, long timeout, Handler<AsyncResult<Lock>> resultHandler) {
...
if (clusterManager == null) {
getLocalLock(name, timeout, resultHandler);
} else {
...
}
}
acquire()
使用ConcurrentHashMap.compute
在引擎盖下:
因此,如果您真的想拥有自己的实现,您可以从上面的代码中获得灵感。不,为什么要这样做?您的
如果(isLocked)
也是不安全的。如果(isLocked)是原子的,则可以。曾经在非阻塞环境中工作过吗?是的,在内部它实际上使用低级别阻塞。如果它是原子的,那么安全的方法是只检查值本身。没有任何东西可以保证它不会在您的检查和您进入下一行的那一刻变为假-r.run()
调用。isLocked
在我看来不是原子的。您在持有锁的同时更新它,但在不持有同一锁的情况下读取它。所以您要求的构造没有任何有用的效果?只需卸下已同步的
,无需任何更换,您就可以得到您想要的。除非你描述了除“非阻塞”之外的任何有意义的东西。好吧,我同意其中的一些,但是由于这是一个比较常见的用例,我希望有一个库已经处理了这个问题。在我的例子中,单线程执行器不太有效,但这是一种很好的技术。单线程执行器不会自己解决它,因为当前线程将阻塞,直到它能够访问池中的线程。最终,非阻塞锁需要一个特殊的实现。非阻塞锁最有可能使用队列,这是对的。您能否举例说明如何使用java.util.concurrent.locks在对象的监视器上实现非阻塞锁或仅使用字符串键?@AlexanderMills right-java.util.concurrent.locks不直接支持您正在寻找的功能。但与监视器不同,它们允许您测试锁是否已锁定,或在给定延迟内尝试获取锁。在Vert.x中,获取每个线程的锁没有多大意义,因为您的代码可能在不同的线程上执行。@Alexey Soshin,我不同意。.Java通常是一个多线程环境,我们一直在锁定一个线程,这实际上就是synchronized()
的作用。如果你拥有这个线程的话。但是Vert.x使用事件循环实现异步性。是否确实要锁定事件循环?可能不会。是的,对不起,我错了,我要找的所有锁都会锁定内存中的一个对象。我的意思是我不想要一个网络锁,我只想要一个内存锁见我下面的答案。除非你在集群模式下运行,否则你的锁将是内存中的锁。当赏金期结束时,你会接受这一点,但我会看看是否有人提出替代方案。是的,我认为在vert.x中实现这一点是个好主意,async与synchronized关键字的配合也很好,它与Asynchronized框架在不同的级别上发挥作用,因此我不确定它是否会起作用。是的,在阅读更多内容后,我同意,wait()和notify()用于线程,wait()will block and notify将唤醒另一个线程-我同意这些将不起作用,除非我们保证有一个没有先占的单线程环境,否则我认为没有办法避免使用synchronized(){},因为我们显然需要跨线程同步对锁定库的访问,所以有点回到原点。
localAsyncLocks.acquire(vertx.getOrCreateContext(), name, timeout, resultHandler);