ThreadLocal与synchronized多线程并发访问区别2【转】

 

ThreadLocal与synchronized多线程并发访问区别2【转】
2009-11-04 11:50

ThreadLocal

由上面可以知道,使用同步是非常复杂的。并且同步会带来性能的降低。Java提供了另外的一种方式,通过ThreadLocal可以很容易的编写多线程程序。从字面上理解,很容易会把ThreadLocal误解为一个线程的本地变量。其它ThreadLocal并不是代表当前线程,ThreadLocal其实是采用哈希表的方式来为每个线程都提供一个变量的副本。从而保证各个线程间数据安全。每个线程的数据不会被另外线程访问和破坏。

我们把第一个例子用ThreadLocal来实现,但是我们需要些许改变。
Student并不是一个私有变量了,而是需要封装在一个ThreadLocal对象中去。调用ThreadLocal的set方法,ThreadLocal会为每一个线程都保持一份Student变量的副本。所以对student的读取操作都是通过ThreadLocal来进行的。

Java代码
  1. protected Student getStudent() {   
  2.      Student student = (Student)studentLocal.get();   
  3.     if(student == null) {   
  4.          student = new Student();   
  5.          studentLocal.set(student);   
  6.      }   
  7.     return student;   
  8. }   
  9.   
  10. protected void setStudent(Student student) {   
  11.      studentLocal.set(student);   
  12. }  


accessStudent()方法需要做一些改变。通过调用getStudent()方法来获得当前线程的Student变量,如果当前线程不存在一个Student变量,getStudent方法会创建一个新的Student变量,并设置在当前线程中。
    Student student = getStudent();
    student.setAge(age);
accessStudent()方法中无需要任何同步代码。

完整的代码清单如下:
TreadLocalDemo.java

Java代码
  1. public class TreadLocalDemo implements Runnable {   
  2.    private final static   ThreadLocal studentLocal = new ThreadLocal();   
  3.       
  4.    public static void main(String[] agrs) {   
  5.         TreadLocalDemo td = new TreadLocalDemo();   
  6.           Thread t1 = new Thread(td,"a");   
  7.           Thread t2 = new Thread(td,"b");   
  8.            
  9.          t1.start();   
  10.          t2.start();   
  11.           
  12.           
  13.   
  14.   
  15.        }   
  16.       
  17.     /* (non-Javadoc)
  18.       * @see java.lang.Runnable#run()
  19.       */  
  20.     public void run() {   
  21.           accessStudent();   
  22.      }   
  23.   
  24.     public  void   accessStudent() {   
  25.            
  26.          String currentThreadName = Thread.currentThread().getName();   
  27.          System.out.println(currentThreadName+" is running!");   
  28.          Random random = new Random();   
  29.         int age = random.nextInt(100);   
  30.          System.out.println("thread "+currentThreadName +" set age to:"+age);   
  31.          Student student = getStudent();   
  32.          student.setAge(age);   
  33.          System.out.println("thread "+currentThreadName+" first   read age is:"+student.getAge());   
  34.         try {   
  35.          Thread.sleep(5000);   
  36.          }   
  37.         catch(InterruptedException ex) {   
  38.              ex.printStackTrace();   
  39.          }   
  40.          System.out.println("thread "+currentThreadName +" second read age is:"+student.getAge());   
  41.            
  42.      }   
  43.        
  44.     protected Student getStudent() {   
  45.          Student student = (Student)studentLocal.get();   
  46.         if(student == null) {   
  47.              student = new Student();   
  48.              studentLocal.set(student);   
  49.          }   
  50.         return student;   
  51.      }   
  52.        
  53.     protected void setStudent(Student student) {   
  54.          studentLocal.set(student);   
  55.      }   
  56. }  
 

运行程序后,屏幕输出:
b is running!
thread b set age to:0
thread b first read age is:0
a is running!
thread a set age to:17
thread a first read age is:17
thread b second read age is:0
thread a second read age is:17

可见,使用ThreadLocal后,我们不需要任何同步代码,却能够保证我们线程间数据的安全。
而且,ThreadLocal的使用也非常的简单。
我们仅仅需要使用它提供的两个方法
void set(Object obj) 设置当前线程的变量的副本的值。
Object get() 返回当前线程的变量副本

另外ThreadLocal还有一个protected的initialValue()方法。返回变量副本在当前线程的初始值。默认为null

ThreadLocal是怎么做到为每个线程都维护一个变量的副本的呢?
我们可以猜测到ThreadLocal的一个简单实现

Java代码
  1. public class ThreadLocal   
  2. {   
  3.  private Map values = Collections.synchronizedMap(new HashMap());   
  4.  public Object get()   
  5.  {   
  6.   Thread curThread = Thread.currentThread();   
  7.   Object o = values.get(curThread);   
  8.   if (o == null && !values.containsKey(curThread))   
  9.   {   
  10.    o = initialValue();   
  11.    values.put(curThread, o);   
  12.   }   
  13.   return o;   
  14.  }   
  15.   
  16.  public void set(Object newValue)   
  17.  {   
  18.   values.put(Thread.currentThread(), newValue);   
  19.  }   
  20.   
  21.  public Object initialValue()   
  22.  {   
  23.   return null;   
  24.  }   
  25. }  


由此可见,ThreadLocal通过一个Map来为每个线程都持有一个变量副本。这个map以当前线程为key。与synchronized相比,ThreadLocal是以空间换时间的策略来实现多线程程序。

Synchronized还是ThreadLocal?
ThreadLocal以空间换取时间,提供了一种非常简便的多线程实现方式。因为多个线程并发访问无需进行等待,所以使用ThreadLocal会获得更大的性能。虽然使用ThreadLocal会带来更多的内存开销,但这点开销是微不足道的。因为保存在ThreadLocal中的对象,通常都是比较小的对象。另外使用ThreadLocal不能使用原子类型,只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离

内容概要:《2024年中国城市低空经济发展指数报告》由36氪研究院发布,指出低空经济作为新质生产力的代表,已成为中国经济新的增长点。报告从发展环境、资金投入、创新能力、基础支撑和发展成效五个维度构建了综合指数评价体系,评估了全国重点城市的低空经济发展状况。北京和深圳在总指数中名列前茅,分别以91.26和84.53的得分领先,展现出强大的资金投入、创新能力和基础支撑。低空经济主要涉及无人机、eVTOL(电动垂直起降飞行器)和直升机等产品,广泛应用于农业、物流、交通、应急救援等领域。政策支持、市场需求和技术进步共同推动了低空经济的快速发展,预计到2026年市场规模将突破万亿元。 适用人群:对低空经济发展感兴趣的政策制定者、投资者、企业和研究人员。 使用场景及目标:①了解低空经济的定义、分类和发展驱动力;②掌握低空经济的主要应用场景和市场规模预测;③评估各城市在低空经济发展中的表现和潜力;④为政策制定、投资决策和企业发展提供参考依据。 其他说明:报告强调了政策监管、产业生态建设和区域融合错位的重要性,提出了加强法律法规建设、人才储备和基础设施建设等建议。低空经济正加速向网络化、智能化、规模化和集聚化方向发展,各地应找准自身比较优势,实现差异化发展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值