线程之间的共享数据不对

时间:2014-11-17 08:42:04

标签: java multithreading

我的程序存在问题。和数据在多个线程之间共享。它应该在每个Thread添加到它之后给出总和。

public class ThreadPractise implements Runnable
{
    Integer num;
    String name;
    volatile Integer commonSum;
    Object lock;

    public ThreadPractise(Integer i,String threadName ,Integer sum, Object sharedLock) {
        num = i;
        name = threadName;
        commonSum =sum;
        lock = sharedLock;
    }

    @Override
    public void run() {
        Integer cube = calculate(num);
        update(cube);
        System.out.println(Thread.currentThread().getName()+" has commonSum after update as "+commonSum);
    }

    public void update(Integer cube) {
        synchronized (lock) {
            this.commonSum = this.commonSum + cube;
            System.out.println(Thread.currentThread().getName()+" has commonSum as "+commonSum);
        }
    }
    public int calculate(Integer num2) {
        return (num2*num2*num2);
    }

    public static void main(String[] args) {

        Integer sum = new Integer(0);
        Object lock = new Object();
        for(int i=1;i<=3;i++)
        {
            Thread t = new Thread(new ThreadPractise(i, "Thread"+i, sum,lock));
            t.start();
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("Sum of 1^3+2^3+3^3 = "+sum);

    }

}

然而,总和总是0.当我改为AtomicInteger它的工作但我需要这个实现的问题。还请告诉我,我正在做的线程锁定是否正确。

3 个答案:

答案 0 :(得分:4)

您的问题与并发性无关。看看你的main方法。它有一个局部变量sum。永远不会更新此局部变量。相反,您正在更改num实例的ThreadPractise字段引用的对象。此值初始化为sum的值,但是一旦替换num的值,其值就不再与sum相关,因为该值只是被替换但未更新。因此,打印的值仍为0,这是最初分配给sum的值。

你做的只是简单地说:

Integer a = 0;
Integer b = a;
b = 1;                 // does not change a
System.out.println(a); // prints '0'

但在Java中,如果不为此变量赋值,则无法更改变量引用的值。

相反,使用AtomicInteger,您将可变实例传递给您的主题。您现在正在更新此实例所代表的值,而不是替换num引用的值。这样,numsum变量保持相同,因为它们引用相同的对象。使用不可变Integer无法实现此方法。如果Integer类的方法类似setValue(int),那么您正在执行的操作将sum,而num同样会引用相同的对象。

答案 1 :(得分:2)

Integer是不可变的。您无法将Integer传递给方法,并期望以这种方式获得更新版本。

如果您不想使用AtomicInteger(可以更新,甚至以线程安全的方式,这将是我首选的解决方案),您需要从每个人中检索部分总和线程或让线程在某处更新公共累加器(例如,通过使commonSum静态)。

答案 2 :(得分:2)

Integer个对象是不可变的。虽然Integer中存在的Thread实例最初与您在main方法中声明的实例相同,但每次实例都会将其替换为新实例更改,即每次添加到commonSum。所有线程都将保存对不同Integer对象的引用,并且main方法中的实例不受影响。

您必须将Integer包装到某种对象中才能在主方法和线程之间共享它。 AtomicInteger就是这样做的,并且,作为一个额外的奖励,将为您完成所有同步。