参考:http://blog.csdn.net/cmershen/article/details/51852739
19.Java有没有内存泄露?
当然有了。。。DTSJava模块中还有MLF缺陷呢~~不过DTS里面能报出的内存泄露十分片面,接下来我们全面的了解一下Java的内存泄露。首先,什么叫内存泄露?就是一个对象已经不再使用,但却仍然占据着内存得不到释放。虽然JVM获得的物理内存有限,但大量的内存泄露会导致Java项目运行时效率下降,还有可能抛出OutOfMemory异常。
举个例子:
- 1
- 2
- 3
- 4
- 5
- 6
- 1
- 2
- 3
- 4
- 5
- 6
在这个例子里面,Vector里面装了一些对象,当o=null时,对象o已经不再使用,原来o所在内存区域已经无法取得,但由于v中有o的引用,即使o不再引用那块地址,系统的GC机制也不会释放掉o所在的内存,这就发生了内存泄露。
当然,DTS中物理连接(文件、数据库、网络)未显式关闭,也会造成内存泄露。
20.concurrent包里面都有什么?
有BlockingQueue及其相关的类,跟阻塞队列有关系。
ConcurrentHashMap,ConcurrentLinkedQueue等,这些是相关集合的线程同步版本。
CopyOnWriteArrayList,也是一种并发用的容器,当我们改变这个数组的时候,先复制一个副本,修改这个副本,再复制回去。这样就实现了读写分离,适用于读多写少的并发场景。
CountDownLatch,这个类适用于这种情况:多个线程同时工作,然后其中几个可以随意并发执行,但有一个线程需要等其他线程工作结束后,才能开始。
该类里面维护一个计数器,通过构造器传入一个初始的count,里面有两个常用方法,一个是cutDown(),将计数器的数值-1,还有await(),调用await()的线程将一直阻塞,直到里面的计数器值为0。
CountedCompleter,这是个java8新增的类,我也看不懂是干啥的,有兴趣的读者自行阅读Java文档:http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountedCompleter.html
CyclicBarrier,同步屏障。当有许多线程并发执行时,可以设置一个屏障,让所有线程执行到屏障时阻塞,直到最后一个线程运行到屏障时,才让所有线程继续往下执行。
DelayQueue,一个延迟阻塞队列,里面的对象只有在其到期的时候才能取走,否则阻塞线程。(之前第4期我们探讨过ScheduleThreadPoolExecutor的时候,里面就有这个东西)
Exchanger,可以在两个线程之间交换数据,只能是2个线程,他不支持更多的线程之间互换数据。
Executor一系列,跟线程池有关系。
ForkJoinPool,Fork/Join模式下的线程池。据说是对多核支持比较好。
FutureTask,是Future的实现,用于获取Callable和Runnable对象的执行状态、结果等。
Phaser,是jdk7新增的一个线程同步工具,跟CountDownLatch和CyclicBarrier有些功能是重复的。
Semaphore,就是OS课上学过的信号量,用于控制一个资源可同时被几个线程访问。
SynchronousQueue,是一种队列,这种队列可以用来模拟生产-消费者模型,因为它的元素入队之后要想再入队必须等候一个出队操作。
ThreadLocalRandom,一个线程同步的随机数生成器,在高并发下生成随机数比Random快。
大致就这些了,还有一些类都是与之相关的。
还有两个子包atomic和locks,其中atomic是对一些数的再封装,保证在多线程下这些数的操作都是原子性的。(例如普通的i++
就不是原子的)locks里面则是提供了各种线程同步锁,其中ReentrantLock比较常用。
上面说的都比较泛,如果真的要深度解析java.util.concurrent包中的每一个类,恐怕十篇博文都不够。
21.关于volatile
之前介绍过,volatile是一种比较弱的同步机制,每次访问volatile修饰的变量时,都去内存中读取最新的值。
22.sleep和wait
sleep是Thread类的静态方法,wait是Object类的方法。sleep()是让线程暂停指定的时间,而wait()需在同步方法和同步代码块中使用,让线程放弃对这个对象的锁,直到notify()重新获得对该对象的锁。
23.synchronized和lock的区别
synchronize是加在代码块或方法中,如果加在代码块中,用括号表示需要锁的对象,如果加在方法中,表示这个方法是同步的,锁住的对象是this。
lock需要显式指定加锁和解锁位置,通常要在finally块显示调用unlock()方法。
在底层机制上,synchronize是悲观锁,也就是说其他线程要想操作这个变量只能阻塞,而lock是乐观锁,每次修改都是假设没有冲突而去完成操作,如果出现异常就重试,直到成功为止。乐观锁适用于读比较多,而悲观锁适用于写比较多的情况。
24.synchronized如何实现的?static synchronized又是怎么回事?
如何实现的应该去阅读hotspot VM中的synchronize.cpp的源码,本人的CPP功力几乎为0,就不看了。。。
static synchronized锁住的是这个类本身,也就说明,它能控制该类的所有对象。而不加static的synchronized则不能约束同一类的两个不同对象。