什么是线程安全以及threadlocal为什么是线程安全的

来源:互联网 发布:北京科瑞明软件招聘 编辑:程序博客网 时间:2024/04/30 23:52

什么是线程安全?

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。


线程安全就是说多线程访问同一代码,不会产生不确定的结果。编写线程安全的代码是依靠线程同步。


产生不确定 结果的例子:

定义一个共享数据: 

public static int a = 0;
多线程多该共享数据进行修改: 
private static void plus() {  for (int i = 0; i < 10; i++) {    new Thread() {      public void run() {        a++;        try {          Thread.sleep(1);        } catch (InterruptedException e) {          e.printStackTrace();        }        System.out.println("plus:" + Thread.currentThread().getName() + ": " + a);      }    }.start();  }}
输出结果: 
plus:Thread-5: 5plus:Thread-2: 5plus:Thread-6: 5plus:Thread-9: 5plus:Thread-1: 6plus:Thread-0: 8plus:Thread-4: 8plus:Thread-3: 10plus:Thread-7: 10plus:Thread-8: 10
很明显,在第一次输出a的值的时候,a的值就已经被其他线程修改到5了,显然线程不安全。 


产生确定结果的例子:

利用synchronized关键字将修改a值的地方和输出的地方上锁。让这段代码在某一个时间段内始终只有一个 
线程在执行: 

private static void plus() {  for (int i = 0; i < 10; i++) {    new Thread() {      public void run() {        synchronized (JavaVariable.class) {          a++;          try {            Thread.sleep(1);          } catch (InterruptedException e) {            e.printStackTrace();          }          System.out.println("plus:" + Thread.currentThread().getName() + ": " + a);        }      }    }.start();  }}
输出结果: 
plus:Thread-2: 1plus:Thread-6: 2plus:Thread-7: 3plus:Thread-3: 4plus:Thread-8: 5plus:Thread-4: 6plus:Thread-0: 7plus:Thread-9: 8plus:Thread-5: 9plus:Thread-1: 10
结果正确。 


为什么threadlocal是线程安全的?

首先定义一个ThreadLocal。 

private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {    protected Integer initialValue() {        return 0;    }};
插一句题外话:为什么threadLocal要被声明成静态的?

   这是为了多个线程使用同一个ThreadLocal对象。

  一个线程对应一个ThreadLocal对象,和多个线程使用同一个ThreadLocal对象结果是一样的。详细情况参考链接:http://www.blogjava.net/zhangwei217245/archive/2010/04/24/317651.html
接着上面的话题,也许可以这样: 

private static void plus() throws Exception {  for (int i = 0; i < 10; i++) {    new Thread() {      public void run() {        //1        a = threadLocal.get();        a++;                //2        threadLocal.set(a);        System.out.println("plus:" + Thread.currentThread().getName() + ": " + threadLocal.get());      }    }.start();  }}

它的结果是怎样呢?

全部会输出1。

当然,它无法使多个线程共同修改一个值,并且保持这个值递增。因为threadlocal不是做这个的,它是为了隔离数据的共享,而不是像同步机制一样实现线程间的通信。

但它的结果是可以确定的,所以它是线程安全的。

很明显,在代码“1”的时候,每一个线程都会将threadLocal的初始值0赋值给共享变量a,因为每一个线程从threadLocal.get()拿到的值都是自己threadLocal保存的。所以,就没有所以了。 
所以对于共享变量a来讲,每个线程都会首先将自己threadLocal里面的初始值0赋值给a,然后将共享变量a+1,然后将a+1的值设置到自己的ThreadLocalMap中,其他线程就访问不到了。下一个线程来的时候又会将自己threadLocal里面的初始值0赋值给a,然后将 a+1,然后... 如此周而复始。a只是被在0和1之间改来改去,最终放到每一个线程的threadLocal里面的a+1的值就不再共享。


0 0
原创粉丝点击