0

我需要运行一个名为的 java 程序ArrayHolder,它将运行两个Threads. ArrayHolder会有一个Array. ThreadSevenArray用 7 和ThreadOne1 覆盖其中的每个元素。执行后的结果应该是 7,1,7,1,7,1,7,1 等。我已经解决了这个问题,虽然我不喜欢我的解决方案并且是希望你能提出更好的方法。

ps:两个线程都必须写入所有索引。

public class ArrayHolder {

    private int[] array = {1, 2, 3, 4, 5, 6, 4, 8, 9, 10};

    public void writeInt(int pos, int num) {
        array[pos] = num;
    }

    public static void main(String[] args) {
        ArrayHolder holder = new ArrayHolder();
        ThreadSeven seven = new ThreadSeven(holder, null);
        Runnable one = new ThreadOne(holder, seven);
        Thread thread1 = new Thread(seven);
        Thread thread2 = new Thread(one);
        seven.setThread(one);

        thread1.start();
        thread2.start();

        holder.printArray();
    }

    private void printArray() {
        for (int i = 0; i < 10; i++) {
            System.out.println(array[i]);
        }
    }

public class ThreadSeven implements Runnable {
    private ArrayHolder array;
    private Runnable t;
    private int flag=0;
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            array.writeInt(i, 7);

            flag=(flag+1)%2;
            if (flag==0){
                synchronized(t){
                    t.notify();
                }
            }else{
                synchronized(this){
                    try {
                        this.wait();
                    } catch (InterruptedException ex) {
                        Logger.getLogger(ThreadSeven.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        }
    }
    public ThreadSeven (ArrayHolder ar,Runnable t){
        array=ar;
        this.t=t;
    }
    public void setThread(Runnable t){
        this.t=t;
    }
}

public class ThreadOne implements Runnable {

    private ArrayHolder array;
    private Runnable t;
    private int flag = 0;

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            array.writeInt(i, 1);

            flag = (flag + 1) % 2;
            if (flag == 1) {
                synchronized (t) {
                    t.notify();
                }
            } else {
                synchronized (this) {
                    try {
                        this.wait();
                    } catch (InterruptedException ex) {
                        Logger.getLogger(ThreadSeven.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        }
    }

    public ThreadOne(ArrayHolder ar, Runnable t) {
        array = ar;
        this.t = t;
    }

    public void setThread(Runnable t) {
        this.t = t;
    }
}
4

2 回答 2

2

ThreadSeven 和 ThreadOne 不需要是单独的类;看起来您只是复制/粘贴代码,然后将7in writeInt 更改为 1. 相反,您可以将此值参数化并将其传递给构造函数。然后你会得到类似的东西:

public class ThreadWriter implements Runnable {
    private final int numberToWrite;
    // ...
    public ThreadOne(ArrayHolder ar, Runnable t, int numberToWrite) {
        array = ar;
        this.t = t;
        this.numberToWrite = numberToWrite;
    }
    // ...
}

另一点是你的两个线程必须相互了解;这不能很好地扩展。假设你的下一个作业你的老师说你必须处理三个写线程1, 4, 7, 1, 4, 7, ...;您将不得不更改ThreadOneand的实现ThreadSeven。您现在可以做出的更好的解决方案是让ThreadWriters 本身更笨,并在ArrayHolder课堂上(或与中间ThreadWriterManager课堂)更多地管理他们的互动。

于 2012-11-22T20:51:29.747 回答
0

您的解决方案有一些问题,在我看来它不会打印正确的结果。

a)在打印结果数组之前,您无需等待线程完成

添加thread1.join()and thread2.join()beforeholder.printArray()以防它还没有。

b) 两个线程都立即开始写入,array.writeInt(0, /* 1 or 7 */);之后它们开始相互等待。第一个索引是否正确取决于运气。

c) 在this.wait();没有循环检查条件的情况下继续是不安全的,因为中断可能是由其他线程以外的其他东西引起的。我想在这里这样做是可以的,因为这只是一个练习。

d) 我看到一个潜在的死锁:假设两个线程仍在写入第一个索引。所以两者都不在同步块中。

必须通知另一个的线程这样做,写入下一个索引并进入它自己的等待块。但是第二个线程当时没有等待,所以notify第一个线程什么也没做。第二个线程也进入等待块。

现在两个线程互相等待,不再发生任何事情。

我没有一个很好的简单解决方案给你,因为这个问题非常复杂。

1 线程需要从索引 0 开始写入,然后等到 7 线程写入索引 0 和 1,现在 1 线程写入索引 1 和 2 并等待,依此类推。这是我认为可以确保两个线程都写入每个索引并且结果是 7-1-7-1-.... 的唯一方法。在内部同步访问ArrayHolder将非常棘手,因为它需要确保两者线程已以正确的顺序写入每个索引。

但是我认为您的总体想法还可以。你只需要确保它是安全的

于 2012-11-22T21:14:12.063 回答