在2d飞机上的两个随机步行者

时间:2015-06-21 20:42:33

标签: java multithreading random thread-safety thread-synchronization

所以我有这个多线程程序生成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();

}
}

2 个答案:

答案 0 :(得分:1)

在进行多线程时避免使用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 (/* ... */);

没有线程,没有锁,没有同步,它应该可以顺利运行并且没有伪影。

答案 1 :(得分:0)

  

所以我有这个多线程程序生成2个随机游走者,   每个助行器都是一个单独的线程,因为我需要它们移动   同时。每个步行者在4个方向中的任何一个方向上随机移动。

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

  

第一个问题是我认为stdDraw不是线程安全的   因此没有锁定我的整个功能,它倾向于   无缘无故地在随机点上绘制随机方块和整个事物   变得非常小故障。当我锁定我的功能然后一个   线程变得比另一个慢,因为它有时必须等待   为了锁。所以线程不再是同时的。有没有   解决这个问题?

线程安全性和随机性在这里并不真正相关。如上所述,您希望步行者是随机的。这首先与线程安全无关。简单地说:线程安全意味着如果多个线程共享一个数据结构/地址空间,那么访问它将保证没有竞争条件。 不确定随机点随机广场的意思。锁通常用于授予执行权限或授予对一个或多个共享资源的访问权限。不确定为什么你在这里使用锁,我没有看到共享资源,如果你不知道,我不知道你为什么一次使用锁来控制线程执行#39;首先想要这个。

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

  

我遇到的另一个问题是我希望它能够突破循环   两个步行者相交,但由于某种原因,两个线程不相交   了解对方的立场。一个人认为的立场   另一个总是在(0,0)。

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

这是2D平面,它会知道两个步行者是否相交? (说实话,我并没有考虑StdDraw,但你会发现我想知道。)找到一种方法从StdDraw获取两个随机助行器的两个坐标并检查路口。如果不可能,则使用共享资源,即包含第一随机游走者和第二随机游走者的坐标的数据结构。

你不需要太在意线程安全,因为一个随机漫步者只会读取(而不是写入)其他随机漫步者的值/坐标。

试试看,告诉我们。