Thread safety and Shared Resource

一、Local Variables

Local variables are stored in each thread’s own stack. That means that local variables are never shared between threads:
That also means that all local primitive variables are thread safe

二、Local Object References

If an object created locally never escapes the method it was created in, it is thread safe. In fact you can also pass it on to other methods and objects as long as none of these methods or objects make the passed object available to other threads.
引用在栈中,是不会共享的;对象存放在共享堆中。如果一个对象不离开此方法,则是线程安全的。假设对象为A,若以参数形式传给其他方法或对象,只要这些方法或对象不把A给其他线程,则是线程安全的。

public void someMethod(){

  LocalObject localObject = new LocalObject();

  localObject.callMethod();
  method2(localObject);
}

public void method2(LocalObject localObject){
  localObject.setValue("value");
}

The LocalObject instance in this example is not returned from the method, nor is it passed to any other objects that are accessible from outside the someMethod(). Each thread executing the someMethod() will create its own LocalObject instance and assign it to the localObject reference. Therefore the use of theLocalObject here is thread safe.
LocalObject实例既没有作为返回值,也没将它传给的其他对象(这些对象在someMethod外是可访问的)。每个执行someMethod方法的线程都会创建自己的LocalObject实例和引用。因此,LocalObject使用时线程安全的。

The only exception is of course, if one of the methods called with the LocalObject as parameter, stores the LocalObject instance in a way that allows access to it from other threads.
例外,以LocalObject 为参数的方法存储LocalObject 实例,这个实例能够让其他线程访问。

三、Object Member Variables

Object member variables (fields) are stored on the heap along with the object. Therefore, if two threads call a method on the same object instance and this method updates object member variables, the method is not thread safe. Here is an example of a method that is not thread safe:
类成员变量被存放在堆中。因此,若两个线程调用同一个实例的相同方法,则这个方法更新类成员变量,此时这个方法并不是线程安全的。

public class NotThreadSafe{
    StringBuilder builder = new StringBuilder();

    public add(String text){
        this.builder.append(text);
    }
}

If two threads call the add() simultaneously on the same NotThreadSafe instance then it leads to race conditions. For instance:
若两个线程同时调用相同的 NotThreadSafe实例 的add(),则会引发race conditions

NotThreadSafe sharedInstance = new NotThreadSafe();

new Thread(new MyRunnable(sharedInstance)).start();
new Thread(new MyRunnable(sharedInstance)).start();

public class MyRunnable implements Runnable{
  NotThreadSafe instance = null;

  public MyRunnable(NotThreadSafe instance){
    this.instance = instance;
  }

  public void run(){
    this.instance.add("some text");
  }
}

However, if two threads call theadd() simultaneously on different instances then it does not lead to race condition. Here is the example from before, but slightly modified:

new Thread(new MyRunnable(new NotThreadSafe())).start();
new Thread(new MyRunnable(new NotThreadSafe())).start();

Now the two threads have each their own instance of NotThreadSafe.so their calls to the add doesn’t interfere with each other. The code does not have race condition anymore. So, even if an object is not thread safe it can still be used in a way that doesn’t lead to race condition.
因为两个线程有各自的NotThreadSafe实例,因此线程调用add()方法并不会相互干扰,所以不会有race condition。因此,尽管一个对象是非线程安全的,它也可以被使用,而不会导致race condition。【并不是非线程安全,就一定会引发race condition。race condition引发的条件是多线程对相同资源同时读写】

四、The Thread Control Escape Rule

When trying to determine if your code’s access of a certain resource is thread safe you can use the thread control escape rule:

If a resource is created, used and disposed within
the control of the same thread,
and never escapes the control of this thread,
the use of that resource is thread safe.

Resources can be any shared resource like an object, array, file, database connection, socket etc. In Java you do not always explicitly dispose objects, so “disposed” means losing or null’ing the reference to the object.

Even if the use of an object is thread safe, if that object points to a shared resource like a file or database, your application as a whole may not be thread safe. For instance, if thread 1 and thread 2 each create their own database connections, connection 1 and connection 2, the use of each connection itself is thread safe. But the use of the database the connections point to may not be thread safe.
即使对象的使用是线程安全的,如果对象指向共享资源,应用作为一个整体也许不是线程安全的。例如,线程1和线程2各自创建自己的数据库连接,连接1和连接2,各自的连接本身的使用是线程安全。但是连接指向的数据库使用可能不是线程安全的。
For example, if both threads execute code like this:

check if record X exists
if not, insert record X

If two threads execute this simultaneously, and the record X they are checking for happens to be the same record, there is a risk that both of the threads end up inserting it. This is how:
如果两个线程同时执行,它们校验的记录X恰巧是同个记录,则存在两个线程最终都插入的风险,如下:

Thread 1 checks if record X exists. Result = no
Thread 2 checks if record X exists. Result = no
Thread 1 inserts record X
Thread 2 inserts record X
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值