- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
得到了一个经典问题的不同变体的任务。我们在南北之间有一座桥,n 个对象试图从北穿过,s 个对象试图从南穿过。(每个对象在自己的线程上运行)。在这种情况下,对象是 Farmer。所有线程同时启动,因此输出应根据谁先到达信号量而有所不同。
我知道有人问过这个问题的很多变体,但我似乎找不到一个与我的问题密切相关以至于我能理解的问题。
我已经在我的桥上使用单个 java.util.concurrent.Semaphore 实现了一个功能完美的“一次一个”交叉,但我正在努力升级它以满足下一个的新标准问题。
问题是他们现在必须成对穿过,而且两对必须来自桥的同一侧,所以 2 个可以一起从北方穿过,或者 2 个可以一起从南方穿过,而不是在all 如果那一侧只剩下 1 个(需要无休止地循环尝试穿过)。
我不希望您为我回答我的作业问题,但任何使用 Java 信号量为我指明正确方向的帮助都会很棒。我的理解是我必须让我的信号灯最多有 2 个(很容易)并且我必须锁定桥直到某一侧的 2 个物体准备好通过(不那么容易)。
一次一个穿越 N=3 S=4 的示例输出
问题 2。
N_Farmer1:WAITING桥接。走向南方
N_Farmer2:WAITING桥接。走向南方
N_Farmer3:WAITING桥接。走向南方
S_Farmer1:WAITING桥接。走向北方
S_Farmer2:WAITING桥接。走向北方
S_Farmer3:WAITING桥接。走向北方
S_Farmer4:WAITING桥接。走向北方
N_Farmer1:过桥第 5 步。
N_Farmer1:第 10 步过桥。
N_Farmer1:第 15 步过桥。
N_Farmer1:过桥。
NEON = 1
N_Farmer2:过桥第 5 步。
N_Farmer2:第 10 步过桥。
N_Farmer2:过桥第 15 步。
N_Farmer2:过桥。
NEON = 2
N_Farmer3:过桥第 5 步。
N_Farmer3:第 10 步过桥。
N_Farmer3:第 15 步过桥。
N_Farmer3:过桥。
NEON = 3
S_Farmer2:第 5 步过桥。
S_Farmer2:第 10 步过桥。
S_Farmer2:第 15 步过桥。
S_Farmer2:过桥。
NEON = 4
S_Farmer1:第 5 步过桥。
S_Farmer1:第 10 步过桥。
S_Farmer1:第 15 步过桥。
S_Farmer1:过桥。
NEON = 5
S_Farmer3:过桥第 5 步。
S_Farmer3:第 10 步过桥。
S_Farmer3:第 15 步过桥。
S_Farmer3:过桥。
NEON = 6
S_Farmer4:第 5 步过桥。
S_Farmer4:第 10 步过桥。
S_Farmer4:过桥步骤 15。
S_Farmer4:过桥。
NEON = 7
我的代码 Bridge.java
public class Bridge {
private int crossed; //Count the number of crossings
private Semaphore bridgeSem; //semaphore to only allow 1 crossing at a time
//Constructor
public Bridge() {
crossed=0;
bridgeSem = new Semaphore(1); //one bridge resource, mutual exclusivity
}
//Getters
public int getCrossed() {
return crossed;
}
//Methods
public void cross() {
//Semaphore acquire
try {
bridgeSem.acquire();
crossed++; //increment NEON counter
}
catch (InterruptedException e) {}
}
public void exit() {
//Semaphore release
bridgeSem.release();
}
}
农夫.java:
public class Farmer extends Thread{
private String location; //current location
private String destination; //Opposite location, destination, set in the constructor
private String id; //name
private Bridge bridge; //bridge being used
//constructor
public Farmer(String id, String location, Bridge bridge) {
this.id=id;
this.location=location;
if (location=="North") destination="South"; //Island objects are not necessary for this particular implementation, as our options are merely North or South
else destination="North";
this.bridge = bridge;
System.out.println(id+": Waiting for bridge. Going towards "+destination); //print initial waiting for bridge
}
//getters
public String getLocation() {
return location;
}
public String getID() {
return id;
}
//Do not need setters, none of the instance variables need to change
@Override //initiatied when the thread.start() method is called
public void run() {
//***initiate critical section requiring semaphore***
bridge.cross();
System.out.println(id+": Crossing bridge Step 5.");
System.out.println(id+": Crossing bridge Step 10.");
System.out.println(id+": Crossing bridge Step 15.");
//Sleep for 200 units ,improves readability (else output is too fast)
try {
Thread.sleep(200);
} catch (InterruptedException e) {} //No interrupts implemented, so thread shouldn't be interrupted?
System.out.println(id+": Across the Bridge.");
System.out.println("NEON = "+bridge.getCrossed());
bridge.exit();
//***end critical section***
//Sleep for 20 units, prevents hogging of semaphore(starvation)
try {
Thread.sleep(20);
} catch (InterruptedException e) {}
}//end run
}//下课
主要内容:
public static void main(String[] args) {
System.out.println("Question 2.");
int N=3,S=4; //DEBUG, add file reading later
Bridge bridge = new Bridge(); //create our bridge
Farmer[] f = new Farmer[N+S]; //array of Farmers
//create North farmers
for (int i=0; i<N; i++) {
f[i] = new Farmer("N_Farmer"+(i+1),"North",bridge);
}
//create South farmers
for (int i=N; i<S+N; i++) {
f[i]= new Farmer("S_Farmer"+(i-N+1),"South",bridge);
}
//start all farmers
for (int i=0;i<S+N;i++) {
f[i].start(); //start Farmer Threads. Farmers can run start, as Farmer extends thread
}
}
最佳答案
我使用的解决方案:将交叉相关的内容移至 Bridge 文件大部分相关逻辑在 Farmer.java run() 命令中,还有一点在 Bridge.java 中的 Synchronized 函数中(保留相关计数器)。主要文件主要是文件阅读和启动农民。Farmer Threads 本质上是检查 bridge 还没有统计 2 个北方或 2 个南方的农民,如果没有,它会使用同步桥函数 upThis(Farmer f) 计算当前的一个。 Bridge 会记录有多少北方或南方农民准备就绪。在 Farmer run() 中,如果 North 或 South 命中 2,我们将信号量访问适当的一侧(信号量有 2 个资源),然后我们等到两者都完成(使用同步的 bridge.getExited()==2),然后退出两者其中,并重置所有计数器。现在计数器已重置,Farmer Thread while 循环可以重试。
可能不是最好的解决方案,Farmer 线程在无限 while 循环中运行,不断地重新检查条件,可能并不理想。但据我所知它是有效的,所以我想我会把它扔给任何有类似问题的人。
将把它标记为已解决和正确的解决方案,直到有人用更好的东西回应。
桥.java:
import java.util.concurrent.Semaphore;
public class Bridge {
private int crossed; //Count the number of crossings
private static Semaphore bridgeSem; //semaphore to only allow 1 crossing at a time
private int northWaiting, southWaiting;
private int exited;
//Constructor
public Bridge() {
crossed=0;
bridgeSem = new Semaphore(2); //one bridge resource, mutual exclusivity
northWaiting = southWaiting = 0;
exited = 0;
}
//Getters
public int getCrossed() {
return crossed;
}
//Methods
public synchronized void upCross() {
crossed++;
System.out.println("NEON = "+getCrossed());
}
public synchronized void upThis(Farmer f) {
if (f.getID().startsWith("N")) northWaiting++;
else southWaiting++;
f.counted();
//System.out.println(f.getID()+" is queued to cross"); //DEBUG
}
public synchronized void upExited() {
exited++;
}
public synchronized int getNorth() {
return northWaiting;
}
public synchronized int getSouth() {
return southWaiting;
}
public synchronized int getExited() {
return exited;
}
public synchronized void resetExited() {
exited=0;
}
public synchronized void resetNorth() {
northWaiting=0;
}
public synchronized void resetSouth() {
southWaiting=0;
}
public void cross(Farmer f) {
//Semaphore acquire
try {
bridgeSem.acquire();
System.out.println(f.getID()+": Crossing bridge Step 5.");
System.out.println(f.getID()+": Crossing bridge Step 10.");
System.out.println(f.getID()+": Crossing bridge Step 15.");
//Sleep for 200 units ,improves readability (else output is too fast)
try {
Thread.sleep(200);
} catch (InterruptedException e) {} //No interrupts implemented, so thread shouldn't be interrupted?
System.out.println(f.getID()+": Across the Bridge.");
upCross(); //increment NEON counter, synchronized to avoid print conflicts
//Sleep for 200 units ,improves readability (else output is too fast)
try {
Thread.sleep(200);
} catch (InterruptedException e) {} //No interrupts implemented, so thread shouldn't be interrupted?
}
catch (InterruptedException e) {}
}
public void exit() {
//Semaphore release
upExited();
bridgeSem.release();
}
}
农夫.java:
public class Farmer extends Thread{
private String location; //current location
private String destination; //Opposite location, destination, set in the constructor
private String id; //name
private Bridge bridge; //bridge being used
private boolean finished=false;
private boolean counted = false;
//constructor
public Farmer(String id, String location, Bridge bridge) {
this.id=id;
this.location=location;
if (location=="North") destination="South"; //Island objects are not necessary for this particular implementation, as our options are merely North or South
else destination="North";
this.bridge = bridge;
System.out.println(id+": Waiting for bridge. Going towards "+destination); //print initial waiting for bridge
}
//getters
public String getLocation() {
return location;
}
public String getID() {
return id;
}
public boolean isCounted() {
return counted;
}
//setter
public void setFinished(boolean finished) {
this.finished=finished;
}
public void counted() {
counted=true;
}
//Overrides the Thread toString() method. Called with Thread.getCurrent().toString()
@Override
public String toString() {
return id;
}
@Override //initiatied when the Farmer Thread .start() method is called
public void run() {
//if ready to cross
while (!finished) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
if (bridge.getNorth() != 2 && bridge.getSouth() != 2 && !counted) { //if neither equal 2 yet and we havent added this to the list
bridge.upThis(this); //increments the appropriate north/south counter in a thread safe method, also marks this thread as counted=true
}
if (counted && bridge.getNorth()==2 && id.startsWith("N")) { //if this has been counted, and is a northern farmer and there are 2 northern farmers ready
bridge.cross(this);
bridge.exit();
finished=true;
if (bridge.getExited()==2) { //if both successfully crossed reset counts
bridge.resetExited();
bridge.resetNorth();
//System.out.println("Reset exited and North"); //DEBUG
//System.out.println("Exit: "+bridge.getExited()+", North: "+bridge.getNorth()+", South: "+bridge.getSouth()); //DEBUG
}
}
else if (counted && bridge.getSouth()==2 && id.startsWith("S")) { //else if this has been counted, and is a southern farmer and there are 2 southern farmers ready
bridge.cross(this);
bridge.exit();
finished=true;
if (bridge.getExited()==2) { //if both successfully crossed reset counts
bridge.resetExited();
bridge.resetSouth();
//System.out.println("Reset exited and South"); //DEBUG
//System.out.println("Exit: "+bridge.getExited()+", North: "+bridge.getNorth()+", South: "+bridge.getSouth()); //DEBUG
}
}
}
}//end run
}//end class
主要.java:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.NoSuchElementException;
import java.util.Scanner;
import packagename.Bridge;
import packagename.Farmer;
public class MainP2 {
public static void main(String[] args) {
System.out.println("Question 2.");
//File reading
boolean success = false; //looping file input
int N=0,S=0;
String[] input;
Scanner in = new Scanner(System.in);
System.out.println("Enter file name eg input.txt: ");
while (!success) { //loop until a valid file is given
try {
String f = in.nextLine();
Scanner file = new Scanner(new File(f)); //Throws file not found exception
try {
//split by space
input = file.nextLine().split("\\s+");
//set number of north and south farmers
N = Integer.parseInt(input[0].replaceAll("[^0-9]+",""));
S = Integer.parseInt(input[1].replaceAll("[^0-9]+",""));
success = true; //no exception thrown, all went well, break loop
} catch (NoSuchElementException e) {System.out.println("File was empty or invalid! Please enter a valid file.");}
file.close();
} catch (FileNotFoundException e) { System.out.println("File not found! Please enter a valid file.");}
}
in.close();
//end file reading
Bridge bridge = new Bridge(); //create our bridge
Farmer[] f = new Farmer[N+S]; //array of Farmers
//create North farmers
for (int i=0; i<N; i++) {
f[i] = new Farmer("N_Farmer"+(i+1),"North",bridge);
}
//create South farmers
for (int i=N; i<S+N; i++) {
f[i]= new Farmer("S_Farmer"+(i-N+1),"South",bridge);
}
//start all farmers
for (int i=0;i<S+N;i++) {
f[i].start(); //start Farmer Threads. Farmers can run start, as Farmer extends thread
}
}
}
关于java - 用成对的线程(java 信号量)穿越单车道桥,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46579280/
我将 Bootstrap 与 css 和 java 脚本结合使用。在不影响前端代码的情况下,我真的很难在css中绘制这个背景。在许多问题中,人们将宽度和高度设置为 0%。但是由于我的导航栏,我不能使用
我正在用 c 编写一个程序来读取文件的内容。代码如下: #include void main() { char line[90]; while(scanf("%79[^\
我想使用 javascript 获取矩阵数组的所有对 Angular 线。假设输入输出如下: input = [ [1,2,3], [4,5,6], [7,8,9], ] output =
可以用pdfmake绘制lines,circles和other shapes吗?如果是,是否有documentation或样本?我想用jsPDF替换pdfmake。 最佳答案 是的,有可能。 pdfm
我有一个小svg小部件,其目的是显示角度列表(参见图片)。 现在,角度是线元素,仅具有笔触,没有填充。但是现在我想使用一种“内部填充”颜色和一种“笔触/边框”颜色。我猜想line元素不能解决这个问题,
我正在为带有三角对象的 3D 场景编写一个非常基本的光线转换器,一切都工作正常,直到我决定尝试从场景原点 (0/0/0) 以外的点转换光线。 但是,当我将光线原点更改为 (0/1/0) 时,相交测试突
这个问题已经有答案了: Why do people write "#!/usr/bin/env python" on the first line of a Python script? (22 个回
如何使用大约 50 个星号 * 并使用 for 循环绘制一条水平线?当我尝试这样做时,结果是垂直(而不是水平)列出 50 个星号。 public void drawAstline() { f
这是一个让球以对角线方式下降的 UI,但球保持静止;线程似乎无法正常工作。你能告诉我如何让球移动吗? 请下载一个球并更改目录,以便程序可以找到您的球的分配位置。没有必要下载足球场,但如果您愿意,也可以
我在我的一个项目中使用 Jmeter 和 Ant,当我们生成报告时,它会在报告中显示 URL、#Samples、失败、成功率、平均时间、最短时间、最长时间。 我也想在报告中包含 90% 的时间线。 现
我有一个不寻常的问题,希望有人能帮助我。我想用 Canvas (android) 画一条 Swing 或波浪线,但我不知道该怎么做。它将成为蝌蚪的尾部,所以理想情况下我希望它的形状更像三角形,一端更大
这个问题已经有答案了: Checking Collision of Shapes with JavaFX (1 个回答) 已关闭 8 年前。 我正在使用 JavaFx 8 库。 我的任务很简单:我想检
如何按编号的百分比拆分文件。行数? 假设我想将我的文件分成 3 个部分(60%/20%/20% 部分),我可以手动执行此操作,-_-: $ wc -l brown.txt 57339 brown.tx
我正在努力实现这样的目标: 但这就是我设法做到的。 你能帮我实现预期的结果吗? 更新: 如果我删除 bootstrap.css 依赖项,问题就会消失。我怎样才能让它与 Bootstrap 一起工作?
我目前正在构建一个网站,但遇到了 transform: scale 的问题。我有一个按钮,当用户将鼠标悬停在它上面时,会发生两件事: 背景以对 Angular 线“扫过” 按钮标签颜色改变 按钮稍微变
我需要使用直线和仿射变换绘制大量数据点的图形(缩放图形以适合 View )。 目前,我正在使用 NSBezierPath,但我认为它效率很低(因为点在绘制之前被复制到贝塞尔路径)。通过将我的数据切割成
我正在使用基于 SVM 分类的 HOG 特征检测器。我可以成功提取车牌,但提取的车牌除了车牌号外还有一些不必要的像素/线。我的图像处理流程如下: 在灰度图像上应用 HOG 检测器 裁剪检测到的区域 调
我有以下图片: 我想填充它的轮廓(即我想在这张图片中填充线条)。 我尝试了形态学闭合,但使用大小为 3x3 的矩形内核和 10 迭代并没有填满整个边界。我还尝试了一个 21x21 内核和 1 迭代,但
我必须找到一种算法,可以找到两组数组之间的交集总数,而其中一个数组已排序。 举个例子,我们有这两个数组,我们向相应的数字画直线。 这两个数组为我们提供了总共 7 个交集。 有什么样的算法可以帮助我解决
简单地说 - 我想使用透视投影从近裁剪平面绘制一条射线/线到远裁剪平面。我有我认为是使用各种 OpenGL/图形编程指南中描述的方法通过单击鼠标生成的正确标准化的世界坐标。 我遇到的问题是我的光线似乎
我是一名优秀的程序员,十分优秀!