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方法,主要作用是创建时初始化实例。也可以采用下面方式创建;
- //第一次调用get将返回null
- private static ThreadLocal threadLocal = new ThreadLocal();
- //获取线程的变量副本,如果不覆盖initialValue,第一次get返回null,故需要初始化一个SimpleDateFormat,并set到threadLocal中
- public static DateFormat getDateFormat()
- {
- DateFormat df = (DateFormat) threadLocal.get();
- if(df==null){
- df = new SimpleDateFormat(DATE_FORMAT)
- threadLocal.set(df);
- }
- return df;
- }
//第一次调用get将返回null
private static ThreadLocal threadLocal = new ThreadLocal();
//获取线程的变量副本,如果不覆盖initialValue,第一次get返回null,故需要初始化一个SimpleDateFormat,并set到threadLocal中
public static DateFormat getDateFormat()
{
DateFormat df = (DateFormat) threadLocal.get();
if(df==null){
df = new SimpleDateFormat(DATE_FORMAT)
threadLocal.set(df);
}
return df;
}
我们看下我们覆盖的initialValue方法:
- protected T initialValue() {
- return null;//直接返回null
- }
3、threadlocal 和 sysncize 区别 是前者是用时间换空间。后者是用空间换时间
4、原子变量和volatile
您可以通过把对成员变量的访问包围到synchronize代码中,来强制java 总是读取刷新的值。java基本这种知识:如果代码是在多线程中执行的,确保它总是得到对象内所有字段成员变量的最新值。另一种方式是将字段成员变量声明为volatile来让java读取刷新的值,这样做本质上讲是告诉编译器不要对字段成员变量的访问进行优化。
当您使用共享的boolean变量作为线程run循环的条件时,你可能需要将该boolean变量声明为volatile,这确保while循环在每次迭代时都读取更新的boolean值。但是,volatile不能保证线程安全。用volatile的条件是不能参与含自身变量的的表达式。