2016-11-08 117 views
1
object GetDetails{ 
    def apply(outStream: java.io.Writer, someObject: SomeClass){ 
    outStream.write(someObject.detail1) //detail1 is string 
    outStream.write(someObject.detail2) //detail2 is also string 
    outStream.flush() 
    } 
} 

如果这个实现不是线程安全的,我该如何使它线程安全?Scala-如何确定对象是否线程安全?

该功能将与不同的输入同时被调用。

+0

只要输入不同(并且没有连接到下面的同一个流),就没问题。 – Dima

回答

0

有一点需要考虑的是,当两个不同的线程调用同一个函数或与同一个对象交互时,应用程序的“状态”可能会发生改变。在这种情况下,你的“状态”可能是“什么被写入outStream”。

考虑以下情形:

Thread 1         Thread 2 
--------------------      ------------------------------- 
GetDetails(outStream, object1) 
             GetDetails(outStream, object2) 
    outStream.write(object1.detail1) 
              outStream.write(object2.detail1) 
    outStream.write(object1.detail2) 
              outStream.write(object2.detail2) 
              outStream.flush() 
    outStream.flush() 

两个独立的线程两个呼叫GetDetails,共享相同的outStream。这是一个潜在的并发问题,因为写入到outStream的数据不能保证以任何特定的顺序。您可能会得到[object1.detail1, object2.detail1, object1.detail2, object2.detail2][object2.detail1, object1.detail1, object1.detail2, object2.detail2],依此类推。

GetDetails.apply不会更改任何GetDetails的状态,但它确实会更改您传递的Writer的状态;为了确保线程安全,您必须尽力避免同时使用同一个Writer(即上面的场景)。

作为反点,这里是一个非常thread- 安全的方法:

object NotThreadSafe { 
    // mutable state 
    private var currentPrefix = "" 

    def countUp(prefix: String) = { 
    // red flag: changing mutable state, then referring to it 
    currentPrefix = prefix 
    for(i <- 1 to 5) println(s"$currentPrefix $i") 
    } 
} 

如果线程1调用NotThreadSafe.countUp("hello")和线程2调用NotThreadSafe.countUp("goodbye"),输出将取决于currentPrefix = prefix发生最后一次。

你可能最终与

你好1
你好2
再见3 //应该是你好3,但currentPrefix得到了改变
再见1
再见4 //应该是喂4
再见5 //应该已经你好5
再见2
再见3
再见4
再见5

或许多其它的排列中的一个。

这就是为什么Scala倾向于选择“不变性”和“无状态性”的原因之一,因为那些工具根本不需要担心这种问题。

如果您发现自己被迫处理可变状态,通常确保线程安全的最简单方法是确保您的方法一次只能调用一次,即使用​​。在更细粒度的级别上,您希望确保特定的步骤序列不与另一个线程上的该序列的另一个副本交错(例如,我在开始描述的GetDetails场景)。

你也可以看看semaphores但这超出了这个答案的范围。

+0

感谢您的回复。摆脱流和具有该函数返回一个List [String]保证线程安全? –

+0

@AnIllusion如果你的'getDetails'方法不影响其自身本地vals/vars之外的任何状态,那么是的。如果你正在做的是建立一个'List'来返回,那么是的,因为你不影响任何其他状态。 – Dylan

相关问题