如果我有这样的局部变量:
Increment()
{
int i = getFromDb(); // get count for a customer from db
};
这是一个增加的实例类(每次客户 - 一个实例对象 - 进行购买),这个变量线程是否安全?我听说局部变量是线程安全的,因为每个线程都有自己的堆栈等等。
另外,我是否正确地认为这个变量是共享状态?我在思维部门缺乏的是这个变量将与不同的客户对象(例如John,Paul等)一起使用,因此线程安全,但这是有缺陷的思维和并发编程的一点经验。这听起来很天真,但是我在并发编码方面没有很多经验,就像我一般的同步编码一样。
编辑:此外,函数调用getFromDb()不是问题的一部分,我不希望任何人猜测它的线程安全性,因为它只是一个调用来指示值是从一个获取数据的函数赋值的来自db。 :)
编辑2:此外,getFromDb的线程安全性得到保证,因为它只执行读取操作。
答案 0 :(得分:33)
i
被声明为本地(方法)变量,因此只有通常存在于Increment()
的堆栈框架中 - 所以是的,i
是线程安全的......(虽然我无法评论getFromDb
)。
除了 if:
Increment
是一个迭代器块(即使用yield return
或yield break
)i
用于匿名方法(delegate { i = i + 1;}
)或lambda(foo => {i=i+foo;}
在上述两种情况下,有些情况下它可以暴露在堆栈外部。但我怀疑你是否也在做。
请注意, fields (类中的变量)不是线程安全的,因为它们通常会暴露给其他线程。对于static
字段,这一点更加明显,因为所有线程都自动共享相同的字段(线程静态字段除外)。
答案 1 :(得分:5)
您的陈述有两个独立的部分 - 函数调用和赋值。
赋值是线程安全的,因为该变量是本地的。此方法的每次不同调用都将获得自己的局部变量版本,每个版本都存储在内存中不同位置的不同堆栈帧中。
对getFromDb()的调用可能是也可能不是线程安全的 - 取决于它的实现。
答案 2 :(得分:2)
只要变量是方法的本地变量,它就是线程安全的。如果它是静态变量,则默认情况下不会。
class Example
{
static int var1; //not thread-safe
public void Method1()
{ int var2; //thread-safe
}
}
答案 3 :(得分:1)
虽然你的int i是线程安全的,但你的整个案例可能不是线程安全的。正如你所说,你的int i是线程安全的,因为每个线程都有自己的堆栈跟踪,因此每个线程都有自己的i。但是,您的线程都共享同一个数据库,因此您的数据库访问不是线程安全的。您需要正确同步数据库访问,以确保每个线程只在正确的时刻看到数据库。
与通常的并发和多线程一样,如果只读取信息,则无需在数据库上进行同步。一旦两个线程尝试从您的数据库读取/写入同一组信息,您就需要进行同步。
答案 4 :(得分:1)
我将是“线程安全的”,因为每个线程将根据您的建议在堆栈上拥有它自己的i副本。真正的问题是getFromDb()线程安全的内容吗?
答案 5 :(得分:1)
我是一个局部变量,所以它不是共享状态。
如果你的getFromDb()正在读取oracle序列或sql server autoincrement字段,那么db正在处理同步(在大多数情况下,不包括复制/分布式DB),因此你可以安全地返回结果到任何调用线程。也就是说,DB保证每个getFromDB()调用都会获得不同的值。
线程安全通常是一点点工作 - 更改变量的类型很少会让您获得线程安全,因为它取决于线程如何访问数据。您可以通过重新编写算法来节省一些麻烦,以便它使用所有使用者同步的队列,而不是尝试编排一系列锁定/监视器。或者更好的是,如果可能的话,使算法无锁。
答案 6 :(得分:1)
我在语法上是线程安全的。但是,当您分配实例变量的值,实例方法返回值为i时,则共享数据由多个线程操纵。