线程安全问题一定是出现在共享数据上

来源:互联网 发布:傲剑境界升级数据 编辑:程序博客网 时间:2024/06/05 06:33

共享数据的特点

1、能被所有线程访问

2、在内存中只有一份,同一时间只能被一个线程访问         ps:threadlocal主要是为了解决这个问题,使每个线程有它自己的一份数据。

3、修改对其它线程可见                         ps:锁机制主要是解决这个问题,让值的改变可预测。



共享数据的可怕之处

 该线程并没有执行什么代码,变量值却改变了。如果变量值的改变是不可预测的,则不是线程安全的。

给方法加锁(在该方法上属于共享数据的变量值发生改变),就是让变量值的改变可以预测。


比如一个静态变量自增10次,在多线程环境下无法预测其结果。

对自增10次这个方法加锁,就可以线程安全。



Java代码  收藏代码
  1. package com;  
  2. /** 
  3.  * @说明 变量安全测试 
  4.  * @author 崔素强 
  5.  */  
  6. public class ThreadLocalTest {  
  7.       
  8.     public static void main(String[] args) {  
  9.         Runnable accumelatora = new Accumulatort();  
  10.         Thread threada = new Thread(accumelatora, "ThreadA");  
  11.         Thread threadb = new Thread(accumelatora, "ThreadB");  
  12.         threada.start();  
  13.         threadb.start();  
  14.     }  
  15. }  
  16. class Accumulatort implements Runnable {  
  17.     // 静态变量  
  18.     private static int local = 0;  
  19.     @SuppressWarnings("unchecked")  
  20.     public void run() {  
  21.          // 静态变量  
  22.         for (int i = 0; i <= 10; i++) {  
  23.             local += 1;  
  24.             try {  
  25.                 Thread.sleep(500);  
  26.             } catch (Exception e) {  
  27.             }  
  28.             System.out.println(Thread.currentThread().getName() + "-->"  
  29.                     + local);  
  30.         }  
  31.     }  
  32. }  

运行后看控制台输出,很容就发现有时候某线程使用变量时已经被另一个线程修改了


该代码出自链接:http://cuisuqiang.iteye.com/blog/1445941



我们再来看看单例模式:

Java单例模式例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class SingletonClass{
    private static SingletonClass instance=null;
    public static SingletonClass getInstance(){
        if(instance==null){

              instance=new SingletonClass();
                
            }
        return instance;
    }
    private SingletonClass(){}
}
为什么代码这样设计会出现线程安全问题?

因为首先,有静态变量。

从静态变量等于null,到静态变量实例化,是一种对静态变量的修改。

它的结果是不确定的,有2种可能情况:

如果构造函数new SingletonClass();语句的执行是一个很短暂的过程,则不会出现2个以上的线程同时进入

if(instance==null)语句块,执行实例化语句的情况。


如果构造函数new SingletonClass();语句的执行是一个很漫长的过程,一个线程执行实例化未完成,另一个线程

就能进入if(instance==null)语句块,执行实例化语句。程序不允许创建2个一样的静态变量所以会报错。


办法:加锁


懒汉式单例模式
1
2
3
4
5
6
7
8
9
10
11
12
13
public class SingletonClass{
    private static SingletonClass instance=null;
    public static synchronized SingletonClass getInstance()
    {
        if(instance==null)
        {
               instance=new SingletonClass();
        }
        return instance;
    }
    private SingletonClass(){
    }
}
将instance方法加上synchronized进行限定,确实可以解决线程安全问题,但会造成多线程调用该方法时串行执行,效率低下

如何改进呢?以下代码既可以保证线程安全又可以提高多线程并发的效率。

双重锁的形式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public static class Singleton{
    private static Singleton instance=null;
    private Singleton(){
        //do something
    }
    public static Singleton getInstance(){
        if(instance==null){
            synchronized(Singleton.class){
                if(null==instance){
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }
}

0 0
原创粉丝点击