Sha*_*n00 71 java synchronization
我有一个进程A,它在内存中包含一组带有一组记录的表(recordA,recordB等......)
现在,这个进程可以启动许多影响记录的线程,有时我们可以有2个线程试图访问同一条记录 - 这种情况必须被拒绝.特别是如果一个记录被一个线程锁定,我希望另一个线程中止(我不想BLOCK或WAIT).
目前我这样做:
synchronized(record)
{
performOperation(record);
}
Run Code Online (Sandbox Code Playgroud)
但是这导致了我的问题......因为当Process1正在执行操作时,如果Process2进入,则阻塞/等待同步语句,并且当Process1完成时,它执行操作.相反,我想要这样的东西:
if (record is locked)
return;
synchronized(record)
{
performOperation(record);
}
Run Code Online (Sandbox Code Playgroud)
有关如何实现这一目标的任何线索?任何帮助将非常感激.谢谢,
Jon*_*eet 77
有一点要注意的是,即时你收到这样的信息,它已经过期.换句话说,你可能会被告知没有人拥有锁,但是当你试图获取它时,你会阻止,因为另一个线程取出了检查之间的锁定并试图获取它.
布莱恩是正确的指向Lock
,但我认为你真正想要的是它的tryLock
方法:
Lock lock = new ReentrantLock();
......
if (lock.tryLock())
{
// Got the lock
try
{
// Process record
}
finally
{
// Make sure to unlock so that we don't cause a deadlock
lock.unlock();
}
}
else
{
// Someone else had the lock, abort
}
Run Code Online (Sandbox Code Playgroud)
你也可以花tryLock
一些时间等待 - 所以你可以尝试获取它十分之一秒,然后如果你不能得到它就中止(例如).
(我认为遗憾的是,Java API没有 - 据我所知 - 为"内置"锁定提供相同的功能,就像Monitor
.NET中的类一样.然后,有很多在涉及到线程时,我在两个平台上都不喜欢其他的东西 - 例如,每个对象都有一个监视器!)
Bri*_*new 23
看一下Java 5并发包中引入的Lock对象.
例如
Lock lock = new ReentrantLock()
if (lock.tryLock()) {
try {
// do stuff using the lock...
}
finally {
lock.unlock();
}
}
...
Run Code Online (Sandbox Code Playgroud)
该ReentrantLock的对象基本上是在做同样的事情,传统synchronized
机制,但有更多的功能.
编辑:正如乔恩所指出的,该isLocked()
方法在那一刻告诉你,此后该信息已经过时.该的tryLock()方法会给更可靠的操作(注意,您可以使用此与超时以及)
编辑#2:tryLock()/unlock()
为清楚起见,现在包括示例.
小智 8
虽然使用Lock对象的上述方法是最好的方法,但如果必须能够使用监视器检查锁定,则可以完成.但是,它确实附带了健康警告,因为该技术无法移植到非Oracle Java VM,并且在未来的VM版本中可能会中断,因为它不是受支持的公共API.
这是怎么做的:
private static sun.misc.Unsafe getUnsafe() {
try {
Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void doSomething() {
Object record = new Object();
sun.misc.Unsafe unsafe = getUnsafe();
if (unsafe.tryMonitorEnter(record)) {
try {
// record is locked - perform operations on it
} finally {
unsafe.monitorExit(record);
}
} else {
// could not lock record
}
}
Run Code Online (Sandbox Code Playgroud)
我的建议是只有在你不能重构你的代码以使用java.util.concurrent Lock对象以及你是否在Oracle VM上运行时才使用这种方法.
我发现了这个,我们可以Thread.holdsLock(Object obj)
用来检查对象是否被锁定:
true
当且仅当当前线程在指定对象上保存监视器锁时返回.
请注意,Thread.holdsLock()
返回false
如果锁被持有的东西,并调用线程是不是持有锁的线程.