二维平面上的两个随机游走者

Two random walkers on a 2d plane

所以我有这个生成 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);

}
}

//主要

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();

}
}

So I have this multithreaded program that generates 2 random walkers, each walker is a separate thread since I need them to move simultaneously. Each walker randomly moves in any of the 4 directions.

你明确表示你想要两个随机行走器,四个方向中的任何一个由两个行走器中的任何一个随机选择。所以我们坚持这个要求。

The first problem is that I think stdDraw is not thread safe and therefore without having a lock around my entire function it tends to draw random squares at random points for no reason and the whole thing becomes pretty glitchy. When I put a lock around my function then one thread becomes slower than the other one, since it sometimes has to wait for the lock. So the threads are not simultaneous anymore. Is there a solution to this?

线程安全性和随机性在这里并不真正相关。如上所述,您希望助行器是随机的。这首先与线程安全无关。简单地说:线程安全是指如果多个线程共享一个数据structure/addressspace,那么保证对它的访问没有竞争条件。 不确定 无缘无故 在随机点的随机方块是什么意思。锁通常用于授予执行权限,或授予对一个或多个共享资源的访问权限。不知道你为什么在这里使用锁,我没有看到共享资源,我不明白你为什么使用锁来 control 一个线程执行,如果你不这样做的话一开始就不想这个。

两个随机游走者是独立的,我看到的唯一共享资源是二维平面。 如果你想让两个步行者执行 simultaneously/concurrently 那么你不应该像我想的那样使用锁。 我什至不确定线程​​安全是否真的是这里的问题,也许你不需要线程安全?

The other problem I have is I want it to break out of the loop when the two walkers intersect, but for some reason the two threads don't know about the positions of each other. One thinks that the position of the other one is always at (0,0).

哦,这是一个很好的跟进问题。也许那时有共享资源?那么它必须是线程安全的吗?

那是二维平面,哪知道两个步行者相交不相交? (老实说,我没有调查 StdDraw,但我想你会知道的。)找到一种方法从 StdDraw 中获取两个随机游走者的两个坐标并检查路口。如果那不可能,则使用共享资源,即包含第一个随机游走者和第二个随机游走者坐标的数据结构。

您不需要太在意线程安全,因为一个随机游走程序只会读取(而不是写入)另一个随机游走程序的values/coordinates。

试试看,然后告诉我们。

在多线程时避免 Math.random() - 在您的 Walker 构造函数中创建一个 r = new Random(),并将其用作 r.nextDouble().

而不是大if,取两个分支之间的差异(只是几种颜色)并将它们放在构造函数中。此外,线程具有单独的命名空间。您不需要将 xx2 分开 - 每个线程都有自己的私有 x,对其他线程不可见。您的代码最终可能会缩减 1/2 的大小。

就同步而言,您有两个问题。第一个问题是 StdDrawbuilt 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 (/* ... */);

没有线程,没有锁,没有同步,它应该可以流畅地工作,没有伪影。