0

我有以下班级表现得很糟糕。它由 3 个线程类组成,顺序不正确,输出也不正确。任何人都知道如何纠正?

输出 -

ANOTHER MY_INT to 1
Got Change for MY_INT : 1
Incrementing MY_INT to 1
Incrementing MY_INT to 2
Got Change for MY_INT : 2
ANOTHER MY_INT to 2
Incrementing MY_INT to 3
ANOTHER MY_INT to 3
Got Change for MY_INT : 3
Incrementing MY_INT to 4
Got Change for MY_INT : 4
ANOTHER MY_INT to 4
Incrementing MY_INT to 5
ANOTHER MY_INT to 5
Got Change for MY_INT : 5
MY_INT:: 5

代码:

public class VolatilityTest {

private static int MY_INT = 0;

/**
 * @param args
 * @throws InterruptedException 
 */
public static void main(String[] args) throws InterruptedException {

    VolatilityTest vt = new VolatilityTest();
    vt.changeListener.start();
    vt.changeMaker.start();
    vt.anotherChangeMaker.start();

    /*new VolatilityTest().changeListener.start();
    new VolatilityTest().changeMaker.start();
    new VolatilityTest().anotherChangeMaker.start();*/
}

Thread changeListener = new Thread(new Runnable() {

    @Override
    public void run() {
            synchronized (this) {
                int local_value = MY_INT;
                while (local_value < 5) {
                    if (local_value != MY_INT) {
                        System.out.println("Got Change for MY_INT : "
                                + MY_INT);
                        local_value = MY_INT;
                    }
                }
            }
        }
});

Thread changeMaker = new Thread(new Runnable() {

    @Override
    public void run() {
            synchronized (this) {
                int local_value = MY_INT;
                while (MY_INT < 5) {
                    System.out.println("Incrementing MY_INT to "
                            + (local_value + 1));
                    MY_INT = ++local_value;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
            System.out.println("MY_INT:: "+MY_INT);
    }
});

Thread anotherChangeMaker = new Thread(new Runnable() {

    @Override
    public void run() {
            synchronized (this) {
                int local_value = MY_INT;
                while (MY_INT < 5) {
                    System.out.println("ANOTHER MY_INT to "
                            + (local_value + 1));
                    MY_INT = ++local_value;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    }
});

}
4

3 回答 3

9

您正在使用每个线程来同步其关键部分。您必须使用共享对象,否则处于线程的关键部分不会阻止其他线程进入它们的。

也就是说,在两个不同的线程中

// Thread 1
synchronize(this) {
    pointA
}

// Thread 2
synchronize(this) {
    pointB
}

意味着程序可以pointA同时pointB进行。

使用共享对象将关键部分相互锁定。

此外,认为同步关键部分只会阻止同时执行,但不会强制它们以给定的顺序执行。

更新:

你需要做什么来同步添加

// add; any object can be used
private static Object sync_instance = new Object();

// and each synchronized section
synchronized(sync_instance) {...}
于 2013-08-31T07:34:48.370 回答
2

当您在this每个线程上同步时,将获得独立的锁(this指向封闭的匿名Runnable()实例)。所以 3 个线程有 3 个锁,因此一个线程可以以任何顺序独立于另一个线程执行。

您需要一个通用锁来保护您的共享变量 MY_INT。您可以使用 VolatilityTest.class 作为锁来保护 MY_INT 静态变量。

Object lock = VolatilityTest.class;

最好使用单独的锁定对象

Object lock = new Object();
.
.
.
synchronized(lock)

为了同步执行顺序

你还需要使用等待

synchronized(lock)
while(condition)lock.wait();

在每个线程中等待特定条件并在完成时通知

synchronized(lock)
lock.notifyAll()

这是使用隐式锁定进行并发编程的传统方式。但是,您可能会在决定之前考虑更新的高级 java.util.concurrent 构造。特别CyclicBarrier注意控制评估顺序

于 2013-08-31T08:26:33.950 回答
0

如果我理解正确,您需要一个线程安全计数器。

如果是这样,请不要尝试同步摆弄计数器的线程。相反,使用本身是线程安全的AtomicInteger 。因此,您可以synchronized从线程中删除语句。

private static AtomicInteger MY_INT = new AtomicInteger(0);

在更改侦听器中,使用:

int local_value = MY_INT.get();

变革者确实做到了

System.out.printline( "Incremented to " + MY_INT.incrementAndGet());
于 2013-08-31T09:02:13.620 回答