所以我有这个多线程程序生成2个随机游走者,每个步行者都是一个单独的线程,因为我需要它们同时移动。每个步行者在4个方向中的任何一个方向上随机移动。第一个问题是我认为stdDraw不是线程安全的,因此没有锁定我的整个函数,它倾向于在随机点无缘无故地绘制随机点,整个事情变得非常小故障。当我在我的函数周围锁定时,一个线程变得比另一个线程慢,因为它有时必须等待锁定。因此,威胁不再是同时发生的。这个问题有方法解决吗?我遇到的另一个问题是我希望它在两个步行者相交时突破循环,但由于某种原因,两个线程不知道另一个的位置。一个人认为另一个人的位置总是在(0,0)。谢谢!
import java.awt.Color;
public class WalkerThread implements Runnable {
String name;
static Integer lock = new Integer(1000);
int num;
static int steps = 0, steps2 = 0;
static int x = 0, y = 0;
static int x2 = -1, y2 = -2;
public WalkerThread(String s, int n) {
this.name = s;
this.num = n;
}
@Override
public void run() {
int N = 10;
StdDraw.create(600, 600);
StdDraw.setScale(-N, -N, +N, +N);
StdDraw.clear(Color.gray);
do {
synchronized (lock) {
if (num == 1) {
StdDraw.go(x, y);
StdDraw.setColor(Color.white);
StdDraw.spot(0.9, 0.9);
double r = Math.random();
if (r < 0.25)
x--;
else if (r < 0.50)
x++;
else if (r < 0.75)
y--;
else if (r < 1.00)
y++;
steps++;
StdDraw.setColor(Color.blue);
StdDraw.go(x, y);
StdDraw.spot(0.9, 0.9);
StdDraw.pause(40);
}
if (num == 2) {
StdDraw.go(x2, y2);
StdDraw.setColor(Color.yellow);
StdDraw.spot(0.9, 0.9);
double r2 = Math.random();
if (r2 < 0.25)
x2--;
else if (r2 < 0.50)
x2++;
else if (r2 < 0.75)
y2--;
else if (r2 < 1.00)
y2++;
steps2++;
StdDraw.setColor(Color.green);
StdDraw.go(x2, y2);
StdDraw.spot(0.9, 0.9);
StdDraw.pause(40);
}
}// lock
/*String pict = steps + ".png";
StdDraw.save(pict);*/
//if (posX == posX2 && posY == posY2) break;
} while ((Math.abs(x) < N && Math.abs(y) < N) && (Math.abs(x2) < N && Math.abs(y2) < N));
System.out.printf("Total steps of %s is %d and %d \n", name, steps, steps2);
}
}
// MAIN
public class Walkers{
public static void main(String[] args) {
Thread t1 = new Thread(new WalkerThread("one", 1));
Thread t2 = new Thread(new WalkerThread("two", 2));
t1.start();
t2.start();
}
}
答案 0 :(得分:1)
在进行多线程时避免使用Math.random()
- 在Walker构造函数中创建r = new Random()
,并将其用作r.nextDouble()
。
取代大if
,取两个分支之间的差异(只有几种颜色)并将它们放在构造函数中。此外,线程具有单独的命名空间。您不需要将x
和x2
分开 - 每个线程都有自己的私有x
,其他线程不可见。你的代码大概可以达到1/2的大小。
就同步而言,你有两个问题。第一个问题是StdDraw
是built on Swing(例如,它在JFrame中运行),这不是线程安全的。特别是,所有绘图必须在名为事件线程的事情中发生。这意味着您应该将所有绘图代码放在
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
synchronized (lock) {
// ... your calls to StdDraw here ...
}
}
});
但是,这会打开一大堆蠕虫。首先,绘图代码需要访问您的数据,因此您希望防止这些数据同时更改。您可以使用更多synchronized (lock) { ... }
来保护它,但这意味着在任何给定时刻只会执行一个线程。这不是多线程的用途。
更简单的答案是,看看Elyasin的答案,忘记并行执行(这里真的不需要),并且接受轮流:
do {
bool turn = false;
// ... current init code here
if (turn) {
// ... current code for num==1
} else {
// ... current code for num==2
}
turn = !turn; // reverse turn for next round
} while (/* ... */);
没有线程,没有锁,没有同步,它应该可以顺利运行并且没有伪影。
答案 1 :(得分:0)
所以我有这个多线程程序生成2个随机游走者, 每个助行器都是一个单独的线程,因为我需要它们移动 同时。每个步行者在4个方向中的任何一个方向上随机移动。
你明确表示你想要两个随机助行器,四个方向中的任何一个都由两个步行者中的任何一个随机选择。所以我们坚持这个要求。
第一个问题是我认为
stdDraw
不是线程安全的 因此没有锁定我的整个功能,它倾向于 无缘无故地在随机点上绘制随机方块和整个事物 变得非常小故障。当我锁定我的功能然后一个 线程变得比另一个慢,因为它有时必须等待 为了锁。所以线程不再是同时的。有没有 解决这个问题?
线程安全性和随机性在这里并不真正相关。如上所述,您希望步行者是随机的。这首先与线程安全无关。简单地说:线程安全意味着如果多个线程共享一个数据结构/地址空间,那么访问它将保证没有竞争条件。 不确定随机点随机广场的意思。锁通常用于授予执行权限或授予对一个或多个共享资源的访问权限。不确定为什么你在这里使用锁,我没有看到共享资源,如果你不知道,我不知道你为什么一次使用锁来控制线程执行#39;首先想要这个。
两个随机游走者是独立的,我看到的唯一共享资源是2D平面。 如果你想让两个步行者同时/同时执行,那么你不应该像我想象的那样使用锁。 我甚至不确定线程安全是否真的存在问题,也许你不需要线程安全?
我遇到的另一个问题是我希望它能够突破循环 两个步行者相交,但由于某种原因,两个线程不相交 了解对方的立场。一个人认为的立场 另一个总是在(0,0)。
哦,现在这是一个很好的跟进问题。也许有一个共享资源呢?它必须是线程安全的吗?
这是2D平面,它会知道两个步行者是否相交? (说实话,我并没有考虑StdDraw
,但你会发现我想知道。)找到一种方法从StdDraw
获取两个随机助行器的两个坐标并检查路口。如果不可能,则使用共享资源,即包含第一随机游走者和第二随机游走者的坐标的数据结构。
你不需要太在意线程安全,因为一个随机漫步者只会读取(而不是写入)其他随机漫步者的值/坐标。
试试看,告诉我们。