java的引用
(1) 、强引用:程序中普遍存在的。类似:“Object o = new Object();”,只要引用还存在,垃圾回收器就不会回收被引用的对象实例。
(2) 、软引用:用来描述一些有用但是非必须的对象,对于软引用关联的对象,在系统将要发生内存溢出之前,将会把这些对象实例列进回收范围内进行二次回收(相当于多了一次被回收的机会),如果这次垃圾回收还没有足够的内存,才会跑出内存溢出的异常。使用SoftReference类实现软引用。
(3) 、弱引用:用来描述非必需的对象。但它的强度比软引用更弱一些,被软引用的对象实例只能存活到下次垃圾回收之前。当下次垃圾回收时,无论内存是否足够,都会回收掉被软引用的对象实例。使用WeakReference类实现弱引用。ThreadLocal中的就是软引用。
(4) 、虚引用:也被称为幽灵引用或者幻影引用。是最弱的一种引用。为一个对象设置虚引用的唯一目的就是在这个对象实例在被垃圾回收器回收时收到一个系统通知。使用PhantomReference类来实现。
ThreadLocal
原理:每一个Thread都维护一个ThreadLocalMap,这个映射表的key就是ThreadLocal实例本身,value是真正存储的值,实际上ThreadLocal并不存储值,而只是作为一个key从ThreadLocalMap中获取value值。这个map是使用ThreadLocal的弱引用作为key的,弱引用在gc时会被回收。
ThreadLocal使用时会造成两个问题:
(1) 内存泄漏:由于ThreadLocalMap的生命周期跟Thread 一样长,如果没有手动删除对应key 就会导致内存泄漏,而不是因为弱引用。通过调用set,get以及remove方法来回收弱引用。使用完毕后调用remove可以避免。
(2) 线程不安全:ThreadLocal本质上保存的是一个引用,而ThreadLocal指向的是同一个对象的时候,当有一个对象改了里面的数据,其他线程访问的时候,访问的是堆上这个对象唯一的实例。如何避免:对于每一个线程而言,应该new出来一个单独的对象给ThreadLocal。
等待和通知的标准范式
等待
Syn(对象){
While(条件不满足){
对象.wait();
}
//处理业务逻辑
}
通知
Syn(对象){
//业务逻辑,改变条件
对象.notify()/notifyAll();
}
锁的几点说明
1、一个对象调用了wait方法后,会释放掉这个对象的锁,而notify()和notifyAll()不会释放锁,只有在执行完syn代码块后才会释放锁。
2、错误加锁的原因其实是对象有变化了,导致加锁失败
3、Volatile关键字其实是最轻量级的锁,原因是volatile获取的最新的值,用在一写多读的场景中
4、调用yield()、sleep()、wait()、notify()等方法对锁有何影响?
答:yield()、sleep()被调用后,都不会释放当前线程所持有的锁。调用wait()方法后,会释放当前线程持有的锁,而且当前被唤醒后,会重新去竞争锁,锁竞争到后才会执行wait 方法后面的代码。调用notify()系列方法后,对锁无影响,线程只有在syn 同步代码执行完后才会自然而然的释放锁,所以notify()系列方法一般都是syn 同步代码的最后一行。
5、数据库的连接池都是使用了等待超时模式实现的。