ThreadLocal和单例对象比较

Posted weishao-lsv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThreadLocal和单例对象比较相关的知识,希望对你有一定的参考价值。

单例对象: 自始至终只有一个对象

当线程并发,每个线程需要自己独立的资源变量处理不同的业务时,单例对象远远不能满足需求

因此可以采用ThreadLocal模式 : 每个线程有自己独立的资源变量    而且每个线程的资源是独享的  其他线程不能访问和修改

笔者刚开始工作时候使用的Struts2,也曾略读过Struts2源码;就个人而言 虽然和现在对比已经过时,但是Struts2的设计思想还是很不错的,每个请求对应一个Action对象

也是ThreadLocal的代表,除去Struts2的标签和OGNL,整体性能也是不错的,读者有兴趣可以自己研究一下

 

单利模式:

//单例模式 私有构造  只有一个对象
public class Singleton{
    private static Singleton instance = null;
    private Singleton(){}
    public synchronized static Singleton getInstance(){
        if (instance == null) {    
            synchronized (Singleton.class) {    
               if (instance == null) {    
                   instance = new Singleton();   
               }    
            }    
        }    
        return instance;   
    }
}

 

ThreadLocal模式  

  

public class Struts2{
    
    private static ThreadLocal<Struts2> map = new ThreadLocal<Struts2>();
    
    private Struts2(){
        
    }
    
    // synchronized不需要设置    每个线程享有自己独立资源
    public static Struts2 getThreadInstance(){
        Struts2 instance = map.get();
        if(instance == null){
            instance = new Struts2();
            map.set(instance);
        }
        return instance;
    }

    //Strtus2就是这种设计思想
    private String msg;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
    
}

//测试类
public
class TestThreadLocal{ public static void main(String[] args) { for(int i=0;i<2;i++){ new Thread(new Runnable(){ @Override public void run() { int data = new Random().nextInt(); System.out.println(Thread.currentThread().getName() + " has put data :" + data); Struts2.getThreadInstance().setMsg(data+""); //存数据 new UserA().get(); new UserB().get(); } }).start(); } } static class UserA{ public void get(){ Struts2 obj = Struts2.getThreadInstance(); System.out.println("UserB from " + Thread.currentThread().getName() + " 数据是 : "+obj.getMsg() ); } } static class UserB{ public void get(){ Struts2 obj = Struts2.getThreadInstance(); System.out.println("UserB from " + Thread.currentThread().getName() + " 数据是 : "+obj.getMsg() ); } } }


输出结果:

Thread-1 has put data :223586296
Thread-0 has put data :1184404572
UserB from Thread-0 数据是 : 1184404572
UserB from Thread-1 数据是 : 223586296
UserB from Thread-1 数据是 : 223586296
UserB from Thread-0 数据是 : 1184404572

 

备注:每个线程有只属于这个线程的对象,每个线程享有自己独立的副本,内部相当于一个Map key[当前线程] - vlaue[值], 线程结束后  会自动把结束的线程移除,不需要自己remove

 

以上是关于ThreadLocal和单例对象比较的主要内容,如果未能解决你的问题,请参考以下文章

“单例”模式-ThreadLocal线程单例

编写高质量代码改善C#程序的157个建议——建议107:区分静态类和单例

构造私有化和单例设计模式

spring中创建bean对象时多例和单例的区别

面向对象编程模式之“简单工厂和单例“

6.类的定义和单例对象