我有多个线程访问外部资源 - 一个broswer。但是一次只能有一个线程访问它。所以,我正在使用信号量来同步它们。但是,一个线程从GUI获取输入然后访问浏览器获取结果,应优先于其他线程,我不知道如何使用信号量来实现它。
我认为获取信号量后的每个线程都会检查队列中是否有优先级线程等待,如果是,则释放它并再次等待。只有优先级线程一旦被获取就不会释放它。
这是一个很好的解决方案,还是我可以使用Java API中的其他内容?
答案 0 :(得分:7)
Java中没有同步原语可以让你以你想要的方式优先于一个线程优先于其他线程。
但您可以使用其他方法来解决您的问题。不是同步线程,而是让它们生成小任务(例如,Runnable
个对象)并将这些任务放入PriorityBlockingQueue
,其中来自GUI线程的任务具有最高优先级。单个工作线程将从此队列轮询任务并执行它们。这将保证互斥和优先排序。
ThreadPoolExecutor
中有一些特殊的构造函数接受阻塞队列。所以,你需要的就是这样一个执行者,你的PriorityBlockingQueue<Runnable>
提供了一个单独的线程。然后将您的任务提交给执行者,它将负责其余的工作。
如果您决定选择此方法,您可能会对此帖子感兴趣:How to implement PriorityBlockingQueue with ThreadPoolExecutor and custom tasks
答案 1 :(得分:2)
这是一个简单,没有多余的答案。这类似于读/写锁的工作方式,除了每个锁具有独占访问权限(通常所有读取器并行进行)。请注意,它不使用Semaphore
,因为这几乎总是使用错误的构造。
public class PrioLock {
private boolean _locked;
private boolean _priorityWaiting;
public synchronized void lock() throws InterruptedException {
while(_locked || _priorityWaiting) {
wait();
}
_locked = true;
}
public synchronized void lockPriority() throws InterruptedException {
_priorityWaiting = true;
try {
while(_locked) {
wait();
}
_locked = true;
} finally {
_priorityWaiting = false;
}
}
public synchronized void unlock() {
_locked = false;
notifyAll();
}
}
您可以像使用java.util.concurrent中的一种Lock类型一样使用它:
普通线程:
_prioLock.lock();
try {
// ... use resource here ...
} finally {
_prioLock.unlock();
}
&#34;优先级&#34;螺纹:
_prioLock.lockPriority();
try {
// ... use resource here ...
} finally {
_prioLock.unlock();
}
更新:
回应关于&#34;抢先的评论&#34;线程交互:
一般而言,你不能这样做。你可以建立自定义功能,添加&#34;暂停点&#34;到锁定部分,这将允许低优先级线程屈服于高优先级线程,但这将充满危险。
你唯一可以实际做的就是中断工作线程,使其退出锁定的代码块(假设你的工作代码响应中断)。这将允许高优先级线程以低优先级线程丢失进度工作为代价更快地进行(并且您可能还必须实现回滚逻辑)。
为了实现这一点,你需要:
lockPriority()
中,打断&#34;当前线程&#34;如果找到了lock()
/ unlock()
(低优先级)调用之间实现逻辑,以便:
lock()
/ unlock()
(低优先级)调用,以便在中断时重新丢失任何工作答案 2 :(得分:0)
你在这里混淆概念。
信号量只是“同步”线程交互的众多选项之一。他们与线程优先级和线程调度有 nothing 。
另一方面,线程优先级本身就是一个主题。你有Java的手段来影响他们;但这些行动的结果在很大程度上取决于底层平台/操作系统;和JVM实现本身。从理论上讲,使用这些优先级是easy,但正如所说的那样;现实更多complicated。
换句话说:您只能使用您的信号量来确保在一个时间点只有一个线程正在使用您的队列。当CPU周期成为问题时,确保GUI读取线程胜过其他线程完全没有帮助。但如果你幸运的话,问题的答案就是简单的拨打setPriority();使用不同的优先级。