- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一组任务,它们分为两部分enque
和deque
以确保合格(多个)运行首先和然后其他按顺序限定(类似于优先级队列)。
在enque
中,将检查任务,并且仅执行合格
任务,而其他不合格
任务将被阻止。
在deque
内,完成的任务将从queue
中删除,然后notifyAll
被阻塞(实际上是所有其他线程选择<强>合格)。
这是我想要实现的目标的简化演示:
class MyTaskQueue {
private static final Object THE_QUEUE_LOCK = new Object();
public static Map<String, ReentrantLock> taskGroupLock = new HashMap<>();
public static Map<String, Condition> taskGroupCondition = new HashMap<>();
public static void enque(String name, String taskId) {
synchronized (THE_QUEUE_LOCK) {
taskGroupLock.putIfAbsent(name, new ReentrantLock());
taskGroupCondition.putIfAbsent(name, taskGroupLock.get(name).newCondition());
}
synchronized (taskGroupLock.get(name)) {
while (true) {
if (isValid(taskId)) {
break; // Go!!;
} else {
try {
taskGroupCondition.get(name).wait(); // blocked if it's not allowed;
} catch (InterruptedException ignored) {
ignored.printStackTrace();
}
}
}
}
}
public static void deque(String name, String taskId) {
if (taskGroup.containsKey(name) && taskGroup.get(name).contains(taskId)) {
synchronized (THE_QUEUE_LOCK) {
taskGroup.get(name).remove(taskId);
if (taskGroup.get(name).isEmpty()) {
taskGroup.remove(name);
}
synchronized (taskGroupLock.get(name)) {
taskGroupCondition.get(name).notifyAll();
}
}
}
}
}
目前,尽管我检查了所有其他任务(至少大多数)都已正确阻止,但只会执行第一个任务。
但是当我检查taskGroupCondition.get(name)
时,firstWaiter
和lastWaiter
都是null
。
我在这里错过了什么?
任何帮助将不胜感激。
最佳答案
如果我理解正确的话,您问的是以下问题:
MyTaskQueue
开始运行的权限(通过 enque
方法)。enque
方法MyTaskQueue
阻塞,直到请求运行的任务获得资格。MyTaskQueue
通过调用 deque
它已结束运行方法。deque
方法通知所有其他任务,以便检查哪些任务符合条件,然后开始运行。然后我可以看到以下解决方案:
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Random;
import java.util.Set;
public class MyTaskQueue {
private final Map<String, Set<String>> runningTasks;
private String qualifiedTaskId;
public MyTaskQueue(String initialQualifiedTaskId) {
runningTasks = new HashMap<>();
qualifiedTaskId = initialQualifiedTaskId;
}
private synchronized boolean isValid(String taskId) {
return qualifiedTaskId != null && taskId != null && taskId.equals(qualifiedTaskId); //Do your qualification tests here...
}
public synchronized void setQualifiedTaskId(String qualifiedTaskId) {
this.qualifiedTaskId = qualifiedTaskId;
notifyAll(); //Now that the qualification test changed, is time to notify every blocked task.
//This way, all new qualified tasks will also be started. This "notifyAll()" operation is optional.
}
public synchronized void enque(String task, String taskId) {
while (!isValid(taskId)) { //Reentrant lock.
System.out.println("Blocking unqualified task {\"" + task + "\", \"" + taskId + "\"}...");
try { wait(); } catch (InterruptedException ie) { /*Handle the exception...*/ }
}
runningTasks.putIfAbsent(task, new HashSet<>());
runningTasks.get(task).add(taskId);
System.out.println("Starting qualified task {\"" + task + "\", \"" + taskId + "\"}...");
}
//Optional method. Might be needed for example if a Thread
//wants to check if another task is currently running...
public synchronized boolean isRunning(String task, String taskId) {
return runningTasks.containsKey(task) && runningTasks.get(task).contains(taskId);
}
public synchronized void deque(String task, String taskId) {
if (isRunning(task, taskId)) { //Reentrant lock.
//Cleanup:
runningTasks.get(task).remove(taskId);
if (runningTasks.get(task).isEmpty())
runningTasks.remove(task);
//Notify all blocked tasks:
notifyAll();
}
}
public static void main(final String[] args) {
MyTaskQueue q = new MyTaskQueue("qualified");
Random rand = new Random();
new MyThread(q, "Task1", "qualified222", 2500 + rand.nextInt(500)).start();
new MyThread(q, "Task2", "qualified222", 2500 + rand.nextInt(500)).start();
new MyThread(q, "Task3", "qualified", 2500 + rand.nextInt(500)).start();
new MyThread(q, "Task4", "qualified", 2500 + rand.nextInt(500)).start();
new MyThread(q, "Task5", "foreverBlocked", 2500 + rand.nextInt(500)).start();
try { Thread.sleep(3000); } catch (InterruptedException ie) { /*Handle the exception...*/ }
synchronized (q) {
System.out.println("Qualifying tasks of id \"qualified222\"...");
q.setQualifiedTaskId("qualified222"); //Reentrant lock.
}
//Execution of main method never ends, because of the forever blocked task "Task5".
//The "Task5" still runs while waiting for permission... See MyThread for details...
}
}
然后是MyThread
:
public class MyThread extends Thread {
private final String task, taskId;
private final int actionTime; //Dummy uptime to simulate.
private final MyTaskQueue q;
public MyThread(MyTaskQueue q, String task, String taskId, int actionTime) {
this.q = q;
this.task = task;
this.taskId = taskId;
this.actionTime = actionTime;
}
@Override
public void run() {
q.enque(task, taskId); //Wait for permission to run...
System.out.println("Task {\"" + task + "\", \"" + taskId + "\"} is currently running...");
//Now lets actually execute the task of the Thread:
try { Thread.sleep(actionTime); } catch (InterruptedException ie) { /*Handle the exception.*/ }
q.deque(task, taskId); //Declare Thread ended.
}
}
MyThread
是执行所需实际操作的类。
为简单起见,我认为如果任务 id 等于变量(即 qualifiedTaskId
),则该任务是合格的。
还有一个main
测试代码的方法。
遵循示例输出(并且我对行进行了编号):
如您所见,第 1 行到第 7 行是每个线程的初始消息。
然后,第 8 行到第 10 行被调用,因为合格的任务结束了(因此它们被重新阻塞)。
然后,第 11 到 13 行被调用,因为另一个合格的任务结束了(因此它们被重新阻塞)。
然后,在第 14 至 19 行,资格测试发生变化,新的合格任务开始运行。还有一个任务( Task5
)尚未合格。
最后,由于任务 id 等于 "qualified222"
的合格任务,因此调用第 20 至 21 行。结束。
关于java - 如何正确使用Condition来等待和notifyAll而不丢失通知?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51088940/
我在 Ubuntu 10.04 LTS 上运行 Eclipse Galileo。今天 Ubuntu 在我身上崩溃了,重新启动后,我发现 Eclipse 已经完全失去了 Java Perspective
我使用配置了 sonata_user 的 SonataAdminBundle在 config.yml : sonata_user: impersonating: route:
我有 ubuntu 14.04 但它不见了 docker exec sudo docker exec -it ubuntu_bash bash 我希望在现有正在运行的 docker 容器中运行交互式
我正在使用 Ubuntu 8.04/32 位(作为虚拟机)。在一个不是 min 的项目上执行一些 make 时,我得到了错误: g++:/usr/lib/libstdc++.a: 没有这样的文件或目录
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许在 Stack Overflow 上提出有关通用计算硬件和软件的问题。您可以编辑问题,使其成为
我正在尝试获取有关我在 UIImagePicker 中选择的视频的一些数据。 因此,当它进入 UIImagePicker 委托(delegate)方法(如下)时,我知道我需要使用信息字典中的 UIIm
我的网站最近被可能的黑客行为删除了。我上传了备份的文件夹和数据库,但现在我的 View 没有显示。其他一切都有效。我想不出有什么变化,只是上传了几天前的备份。 这些字段在 admin/build/vi
我执行以下操作来设置我的 session ,这是有效的,因为 echo 出现了。但是当我转到下一页或另一页时, session 不存在吗?我做错了什么? $session_start(); if ($
我试图在 BigQuery 中使用这段代码,显然是从 GA 中获取数据,但 _TABLE_SUFFIX 似乎有问题。错误显示“错误:无法识别的名称:_TABLE_SUFFIX at [12:3]”您能
输入:8(2 5 6 9 10 2 7 4)预期输出:(2 7 9 9 12 5 7 6)实际输出:(2 7 9 9) 这是我的大学作业,也是我第一次在这里提问。我不知道为什么,但 10 没有扫描,有
$('div'); // 我在上面的代码中遇到错误。在检查 .js 代码时,我找不到名为 $ 的函数,但根据文档,应该有一个。 最佳答案 试试 http://ajax.googleapis.co
以下简单代码的输出对我来说有点奇怪。它错过了在控制台上打印的 0 到 100 之间的一些数字。 谁能解释一下为什么省略打印?我对并发编程完全陌生。 import java.util.concurren
我正在学习 xamarin 以构建移动应用程序,但我对 Xamarin 和移动应用程序一无所知。我打开了一个空白的移动应用程序,其中有“Hello world”示例并编辑了一些文本,但我的应用程序图标
我正在将一些值存储到 sqlite 数据库中。因此,数据是作为字符串从文本字段收集的,然后转换为 double 并持久化。 这是我试过的 NSDecimalNumber 答案; value.answe
我有一个奇怪的案例。突然,其中一个表中的一些记录(这么多记录)丢失了。首先,我认为这是由我的 PHP 脚本中的错误引起的。但是,我检查了一下,我的脚本中没有DELETE操作,只有UPDATE。有谁知道
我正在复制 NSString来自 NSDictionary进入本地NSString使用 [[NSString alloc] initWithString:] ,对其进行处理(删除一些字符),然后将其发
当保存在根文件夹中时,我的非常基本的 html 页面保持样式。为一个组创建了一个新文件夹,但是当我将页面移动到该文件夹时,它们似乎失去了与 css 文件的连接。 认为问题可能出在链接上,因为它现在
我需要使用 OpenCV 训练一些图像。但问题是,我找不到 opencv_createsamples 程序。我以正常方式安装了 OpenCV,因为我使用的是 Windows 7。这个 opencv_c
我有一个绑定(bind)到 JTable 的 ArrayList。之后 bindingGroup.unbind(); bindingGroup.bind(); (完成刷新数据)我丢失了表格单元格渲
所以基本上我们只是丢失了一个 keystore 和备份 keystore 。但是我们可能知道原始 keystore 的密码。 我的问题是,如果我们知道原始 keystore 的密码,我们可以重新生成
我是一名优秀的程序员,十分优秀!