java 内存消耗以及ThreadLocal理解

来源:互联网 发布:域名算知识产权吗 编辑:程序博客网 时间:2024/06/03 01:27

1、关于java内存消耗:内存的消耗原因:大并发量。 因为请求量很大,造成你要创建大量的线程,而且不能及时的清除和回收已经执行完的变量。导致内存溢出等。这时候,你应该创建钩子,去关闭线程。比如中断线程,interrupt  、设置布尔值、或放一个特殊对象在循环中。

     b、关闭线程时,要先Thread.join(3000),因为关闭线程要一段时间。

     c、线程 stop 方法是一个不安全的方法。必须让线程自然死亡。

2、threadlocal 不是线程,准确的讲是一个线程变量。是一管理对每个线程为每个线程创建和访问任意类型的实例。

  大致意思:Tim Cull碰到一个SimpleDateFormat带来的严重的性能问题,该问题主要有SimpleDateFormat引发,创建一个SimpleDateFormat实例的开销比较昂贵,解析字符串时间时频繁创建生命周期短暂的实例导致性能低下。即使将SimpleDateFormat定义为静态类变量,貌似能解决这个问题,但是SimpleDateFormat是非线程安全的,同样存在问题,如果用‘synchronized’线程同步同样面临问题,同步导致性能下降(线程之间序列化的获取SimpleDateFormat实例)。

    Tim Cull使用Threadlocal解决了此问题,对于每个线程SimpleDateFormat不存在影响他们之间协作的状态,为每个线程创建一个SimpleDateFormat变量的拷贝或者叫做副本,

 创建一个ThreadLocal类变量,这里创建时用了一个匿名类,覆盖了initialValue方法,主要作用是创建时初始化实例。也可以采用下面方式创建;

 

Java代码
  1. //第一次调用get将返回null   
  2. private static ThreadLocal threadLocal = new ThreadLocal();   
  3. //获取线程的变量副本,如果不覆盖initialValue,第一次get返回null,故需要初始化一个SimpleDateFormat,并set到threadLocal中  
  4. public static DateFormat getDateFormat()    
  5. {   
  6.     DateFormat df = (DateFormat) threadLocal.get();   
  7.     if(df==null){   
  8.         df = new SimpleDateFormat(DATE_FORMAT)   
  9.         threadLocal.set(df);   
  10.     }   
  11.     return df;   
  12. }  

 

   我们看下我们覆盖的initialValue方法:

 

Java代码
  1. protected T initialValue() {   
  2.         return null;//直接返回null  
  3.     }  

3、threadlocal 和 sysncize 区别  是前者是用时间换空间。后者是用空间换时间

ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。
 
ThreadLocal不能使用原子类型,只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。
 
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
 
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
 
当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。

 

4、原子变量和volatile

您可以通过把对成员变量的访问包围到synchronize代码中,来强制java 总是读取刷新的值。java基本这种知识:如果代码是在多线程中执行的,确保它总是得到对象内所有字段成员变量的最新值。另一种方式是将字段成员变量声明为volatile来让java读取刷新的值,这样做本质上讲是告诉编译器不要对字段成员变量的访问进行优化。

   当您使用共享的boolean变量作为线程run循环的条件时,你可能需要将该boolean变量声明为volatile,这确保while循环在每次迭代时都读取更新的boolean值。但是,volatile不能保证线程安全。用volatile的条件是不能参与含自身变量的的表达式。

1 0
原创粉丝点击