换句话说,如果线程无法访问锁定,我不希望线程等待(如在同步中),我想线程执行只是在它无法获得锁定时立即返回。
像这样的简单布尔锁可能允许多个线程访问。
private static boolean lockAvailable = true;
private boolean acquireLock() {
if(lockAvailable) {
lockAvailable = false;
return true;
}
return false;
}
我错过了什么吗?实现这一目标的最佳/最简单方法是什么?
编辑:
感谢您指出Semaphore(!)
再看一遍,这段代码是防弹的吗?
private final static Semaphore lock = new Semaphore(1, true);
public void tryAndDoSomething() {
if(lock.tryAcquire()) {
try {
// only single thread can access here at one time
} finally {
lock.release();
}
}
}
更新
我意识到我需要可重入的功能,所以我创建了一个简单的非阻塞重入。为任何对您如何执行此操作感兴趣的人发布代码。任何想要此类功能的人当然应该使用现有的 Java类java.util.concurrent.locks.ReentrantLock:|
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* SimpleNonBlockingLock ensures that only a single thread can call protected code at any one time,
* while allowing other threads to by pass the protected code if the lock is unavailable.
* The thread owning the lock can access any code protected by the lock (the lock is 'reentrant').
* To function correctly the protected code must be executed in a try/finally blocks. The
* finally block must call the tryRelease. Example code:
*
* private final SimpleNonBlockingLock lock = new SimpleNonBlockingLock();
*
* if(lock.tryAcquire()) {
* try {
* // access protected code
* } finally {
* lock.tryRelease();
* }
* }
*
* This code is for demonstration only and should not be used. I have tested it and it 'seems to' work.
* However it may contain horrific bugs!
*
* The Java class java.util.concurrent.locks.ReentrantLock has been around since Java 5.0 and contains all (and more)
* of this functionality. Its also been thoroughly tested!
*/
public class SimpleNonBlockingLock {
// Atomic locking mechanism
private final AtomicBoolean locked = new AtomicBoolean();
// Atomic integer containing the next thread ID to be assigned
private static final AtomicInteger nextId = new AtomicInteger(0);
// Unique ID of thread which currently has lock
private int threadUniqueId = -1;
// Tracks number of tryAcquire calls made by thread with lock
private int lockCount = 0;
// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId = new ThreadLocal<Integer>() {
@Override protected Integer initialValue() {
return nextId.getAndIncrement();
}
};
public synchronized boolean tryAcquire() {
// Allow owning thread to acquire
if(threadUniqueId == getCurrentThreadUniqueId()) {
lockCount++;
return true;
}
// If locked then do not allow
if (locked.get()) {return false;}
// Attempt to acquire lock
boolean attemptAcquire = locked.compareAndSet(false, true);
// If successful then set threadUniqueId for the thread, and increment lock count
if(attemptAcquire) {
threadUniqueId = getCurrentThreadUniqueId();
lockCount++;
}
// Return result of attempt to acquire lock
return attemptAcquire;
}
public synchronized boolean tryRelease() {
if (!locked.get()) {
// Lock is currently available - no need to try and release
return true;
} else {
// Decrement the lock count
lockCount--;
// If lock count is zero we release lock, and reset the threadUniqueId
if(lockCount == 0) {
threadUniqueId = -1;
return locked.compareAndSet(true, false);
}
return false;
}
}
// Returns the current thread's unique ID, assigning it if necessary
public static int getCurrentThreadUniqueId() {
return threadId.get();
}
}
答案 0 :(得分:8)
Java 5引入了explicit locks操作tryLock
。因此,使用显式锁而不是同步块,然后您可以调用tryLock
:
private Lock lock = ...;
private boolean acquireLock() {
if (lock.tryLock()) {
...
return true;
} else {
return false;
}
}
答案 1 :(得分:3)
使用Semaphore
和tryAcquire
方法。
答案 2 :(得分:0)
您应该尝试使用ReentrantLock类。 您可以尝试使用tryLock()或直接调用lock()来获取。确保您学习了ReentrantLock的API。 这是一个简短的例子:
Lock lock = new ReentrantLock();
// block until lock is acquired. Make sure to call unlock in a finally
// statement!
try {
lock.lock();
} finally {
lock.unlock();
}
// or try to gain the lock
boolean success = lock.tryLock();
if(success) {
//some logic..
}
//or try to gain lock within time frame
try {
lock.tryLock(1, TimeUnit.SECONDS);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
答案 3 :(得分:0)
其他人已经指出,有很好的库可以完成所有这些以及更多,但是如果你对实现这类事情感兴趣,那么你需要一些支持比较和设置操作的东西。幸运的是,Java5中有java.util.concurrent.atomic.Atomic *类!
public class MyLock {
private final AtomicBoolean locked = new AtomicBoolean();
public boolean tryLock() {
if (locked.get()) return true;
return locked.compareAndSet(false, true);
}
public boolean unlock() {
if (l!ocked.get()) return true;
return locked.compareAndSet(true, false);
}
}
以上是非常天真的实现,但它显示了如何实现这一点的基本知识是无锁的。
有关并发数据结构的实现细节的更多信息,请参阅Shavit和Herlihy的“多处理器编程的艺术”,当然还有Goetz等人的基本“Java Concurrency in Practice”。
答案 4 :(得分:-3)
是的,你错过了什么(你的解决方案不起作用)
想象两个线程同时到达if()语句,然后传递它。 都将lockAvailable设置为false并返回true
如果您不想违反关键部分规则或使用其他方法,则必须使该功能同步。