在线程之间传递可变数据

时间:2014-08-19 07:15:44

标签: java multithreading concurrency

这是关于Java中多线程的基本问题:我有一个非常大的可变数据结构(确切地说是一棵树)我明白如果我想从两个不同的线程同时修改这个数据结构,我需要使用锁和/或其他类型的线程安全。

但是,在我的情况下,两个线程不需要同时修改数据结构;相反,通常拥有数据结构的线程A应该暂时将后者传递给线程B,并且线程B应该在对它进行一些长时间运行的修改后将数据结构传递回线程A.

如果保证线程不会同时修改数据,那么在线程之间来回传递这个可变数据结构是否是线程安全的吗?

7 个答案:

答案 0 :(得分:12)

如果你能保证线程不会同时修改树(即通过原子方式通过对树的唯一引用),从线程安全的角度来看就没问题。

但数据可见性/一致性是另一个问题。除非树中的所有字段都是(递归地)声明volatile,否则一个线程所做的更改可能不会对另一个线程可见。为避免这种情况,请确保在线程交换树的所有权时获取监视器(充当内存屏障并确保所有写入变为可见)。

答案 1 :(得分:9)

是的,当您在线程之间传递对象时,只要您采取特定步骤以避免内存一致性错误,您所描述的内容就可以正常工作。使用锁定是实现这一目标的一种方法,但还有其他方法 - 更便宜 - 。

tutorial是一个很好的起点。

基本上,您需要确保当线程A将对象传递给线程B时,A 的所有更改都会在 B访问对象之前发生。

JLS还有更多内容,但它相当技术性。

答案 2 :(得分:4)

如果没有进一步的同步保证,这是线程安全。

基本上,如果没有正确的同步(例如synchronized或其他事先发生的JLS保证),就无法确定线程之间的一致可见性。也就是说,即使可能没有"并发修改",也有 no 保证非写入者线程看到对所述对象的修改。

答案 3 :(得分:4)

是的,但这仍然引发了如何在线程之间转移数据所有权的问题。答案是这通常是用锁来完成的;持有锁表示给定的线程当前是允许改变对象的负责人。

当有一个或多个读者和至少一个作者时,注意线程安全是一个问题也是很重要的。仅仅因为两个对象不是同时修改对象,如果一个线程在被突变的同时从结构中读取,它仍然是个问题。

所以,要明白这一点:保持简单,只需使用锁。

答案 4 :(得分:2)

一般来说,它不是,但在许多特定情况下,它可能会发挥作用(只是不依赖于那些)。

锁定会做两件事。

  1. 它可以防止两个线程同时访问相同的数据。
  2. 当锁定时,程序/系统具有的所有缓存都被刷新。这也是为什么java中的关键字被称为synchronized
  3. 的原因

    如果以某种方式你可以建立一个自己锁定的机制(这就是你所说的),你仍然需要确保所有数据在线程之间同步。锁定不是唯一的方法,但它是它的一个附加功能。

答案 5 :(得分:2)

我假设您已经创建了自定义数据结构。

尝试创建dataStructure类Synchronized like this 如果需要,请谨慎使用synchronized块。

如果你需要在所有线程上共享相同的数据,那么创建static Synchronized方法和private static变量,那么即使你错误地创建了dataStructure类的多个实例,它也是线程安全的

答案 6 :(得分:0)

这可以通过一个简单的volatile辅助变量来完成:

class OwnedTree{
    private volatile Thread owner;
    private Tree tree;

    //once a thread calls this with a the!=Thread.currentThread() then it may not use Tree returned from getTree any more
    public void passToThread(Thread thr){
        if(Thread.currentThread().equals(owner))
            owner = thr;//volatile write ensures happens-before
    }

    public Tree getTree(){
        if(!Thread.currentThread().equals(owner))//volatile read ensures happens-before
            throw new IllegalStateException();//or return null;
        return tree;
    }

    public Thread getOwner(){
        return owner;
    }

}

易失性读写的语义确保如果正确使用此类,所有更改都将可见