线程安全和局部变量

如果我有这样的局部变量:

Increment() { int i = getFromDb(); // get count for a customer from db }; 

这是一个增加的实例类(每次客户 – 一个实例对象 – 进行购买),这个变量线程安全吗? 我听说局部变量是线程安全的,因为每个线程都有自己的堆栈等等。

另外,我是否认为这个变量是共享状态? 我在思维部门缺乏的是这个变量将与不同的客户对象(例如John,Paul等)一起使用,因此线程安全,但这是一个有缺陷的思维,并且在并发编程方面缺乏经验。 这听起来很天真,但是我在并发编码方面没有很多经验,就像我一般的同步编码一样。

编辑:此外,函数调用getFromDb()不是问题的一部分,我不希望任何人猜测它的线程安全性,因为它只是一个调用,指示值是从一个从数据库获取数据的函数分配的。 🙂

编辑2:此外,getFromDb的线程安全性得到保证,因为它只执行读取操作。

i被声明为一个本地(方法)变量,所以它通常只存在于Increment()的堆栈框架中 – 所以是的, i是线程安全的……(虽然我不能评论getFromDb )。

除非

  • Increment是一个迭代器块(即使用yield returnyield break
  • i用在一个匿名方法( delegate { i = i + 1;} )或lambda( foo => {i=i+foo;}

在上述两种情况下,有些情况下它可以暴露在堆栈外部。 但我怀疑你是否也在做。

请注意, 字段 (类上的变量) 不是线程安全的,因为它们很容易暴露给其他线程。 static字段更加明显,因为所有线程自动共享相同的字段(线程静态字段除外)。

您的语句有两个独立的部分 – 函数调用和赋值。

赋值是线程安全的,因为该变量是本地的。 此方法的每个不同调用都将获得其自己的局部变量版本,每个版本都存储在内存中不同位置的不同堆栈帧中。

对getFromDb()的调用可能是也可能不是线程安全的 – 取决于它的实现。

只要变量是方法的本地变量,它就是线程安全的。 如果它是静态变量,则默认情况下不会。

 class Example { static int var1; //not thread-safe public void Method1() { int var2; //thread-safe } } 

虽然你的int i是线程安全的,但你的整个案例可能不是线程安全的。 正如你所说,你的int i是线程安全的,因为每个线程都有自己的堆栈跟踪,因此每个线程都有自己的i。 但是,您的线程都共享同一个数据库,因此您的数据库访问不是线程安全的。 您需要正确同步数据库访问,以确保每个线程仅在正确的时刻看到数据库。

与通常的并发和multithreading一样,如果只读取信息,则无需在数据库上进行同步。 一旦两个线程尝试从您的数据库读取/写入同一组信息,您需要同步。

我将是“线程安全的”,因为每个线程将根据您的建议在堆栈上拥有它自己的i副本。 真正的问题是getFromDb()线程的内容是否安全?

我是一个局部变量,因此它不是共享状态。

如果您的getFromDb()正在读取oracle序列或sql server autoincrement字段,那么db正在处理同步(在大多数情况下,不包括复制/分布式DB),因此您可以安全地将结果返回给任何调用线。 也就是说,DB保证每个getFromDB()调用都会获得不同的值。

线程安全通常是一些工作 – 更改变量的类型很少会让您的线程安全,因为它取决于您的线程将如何访问数据。 您可以通过重新编写算法来节省一些麻烦,以便它使用所有使用者同步的队列,而不是尝试编排一系列锁定/监视器。 或者更好的是,如果可能的话,使算法无锁。

我在句法上是线程安全的。 但是,当您分配实例变量的值,实例方法返回值为i时,则共享数据由多个线程操纵。