线程之间的共享数据不正确



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

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 时,它可以工作,但我需要此实现的问题。另外请告诉我我正在做的线程锁定是否正确。

您的问题与并发无关。看看你的main方法。它有一个局部变量sum。此局部变量永远不会更新。相反,您正在更改ThreadPractise实例的num字段引用的对象。此值使用 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同样会引用同一个对象。

Integer是不

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

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

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

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

最新更新