我有两个问题......
我有一个带有函数的类,只能在给定时间由任何一个线程访问。使这个synchronized
函数或synchronized
块仍允许多个线程,因为不同的线程正在类中访问它。如何确保只有一个线程访问此代码? (参见下面的代码示例)
使用synchronized函数,对函数的调用排队。有没有办法只允许最后一次调用该函数来访问代码?因此,如果我当前正在访问我的函数Thread1,那么Thread2和Thread3会尝试访问它(按此顺序),一旦Thread1完成,只有Thread3会被授予访问权。
public void doATask() {
// I create a new thread so the interface is not blocked
new Thread(new Runnable() {
@Override
public void run() {
doBackgroundTask();
}
}).start();
}
private void doBackgroundTask(MyObject obj) {
// perform long task here that is only being run by one thread
// and also only accepts the last queued thread
}
感谢您的帮助!
答案 0 :(得分:2)
如果示例中的第二个线程只能return
,则可以使用锁的组合并跟踪执行该方法的最后一个线程。它看起来像这样:
private volatile Thread lastThread;
private final ReentrantLock lock = new ReentrantLock();
private void doBackgroundTask(Object obj) throws InterruptedException {
Thread currentThread = Thread.currentThread();
lastThread = currentThread;
try {
// wait until lock available
lock.lockInterruptibly();
// if a thread has arrived in the meantime, exit and release the lock
if (lastThread != currentThread) return;
// otherwise
// perform long task here that is only being run by one thread
// and also only accepts the last queued thread
} finally {
lock.unlock();
}
}
带有额外日志记录的完整工作测试,显示线程交错并且T2退出而不执行任何操作:
class Test {
private volatile Thread lastThread;
private final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws Exception {
final Test instance = new Test();
Runnable r = new Runnable() {
@Override
public void run() {
try {
instance.doBackgroundTask(null);
} catch (InterruptedException ignore) {}
}
};
Thread t1 = new Thread(r, "T1");
Thread t2 = new Thread(r, "T2");
Thread t3 = new Thread(r, "T3");
t1.start();
Thread.sleep(100);
t2.start();
Thread.sleep(100);
t3.start();
}
private void doBackgroundTask(Object obj) throws InterruptedException {
Thread currentThread = Thread.currentThread();
System.out.println("[" + currentThread.getName() + "] entering");
lastThread = currentThread;
try {
// wait until lock available
lock.lockInterruptibly();
// if a thread has arrived in the meantime, exit and release the lock
if (lastThread != currentThread) return;
// otherwise
// perform long task here that is only being run by one thread
// and also only accepts the last queued thread
System.out.println("[" + currentThread.getName() + "] Thinking deeply");
Thread.sleep(1000);
System.out.println("[" + currentThread.getName() + "] I'm done");
} finally {
lock.unlock();
System.out.println("[" + currentThread.getName() + "] exiting");
}
}
}
输出:
[T1] entering
[T1] Thinking deeply
[T2] entering
[T3] entering
[T1] I'm done
[T1] exiting
[T2] exiting
[T3] Thinking deeply
[T3] I'm done
[T3] exiting
答案 1 :(得分:2)
你想要的可能是一个工作线程,等待信号做一些工作。 doATask()
只是发送一个信号来触发工作。累积信号相当于一个信号。
final Object lock = new Object();
MyObject param = null;
public void doATask(arg)
synchronized(lock)
param=arg;
lock.notify();
MyObject awaitTask()
synchronized(lock)
while(param==null)
lock.wait();
tmp=param;
param=null;
return tmp;
// worker thread
public void run()
while(true)
arg = awaitTask();
doBackgroundTask(arg);