线程状态
new新生,runnable可运行,blocked堵塞,dead死亡
线程堵塞的原因和恢复方式:
线程睡眠-睡眠结束,经过指定的毫秒数
i/o堵塞-i/o操作完成,
等待锁定-锁可用,等待的锁被其它线程释放或者等待超时
等待-通知,等待某个触发条件,当另外一个线程发出信号量表明条件已经发生变化。则回唤醒该线程进入可运行状态,重新判断等待条件
线程死亡的原因:
1 run方法正常退出导致正常死亡
2 未捕获的异常导致run方法意外终止而猝死
java.util.concurrent.locks包
Lock 是一个接口
ReentrantLock 可用来保护临界区的可重用锁
ReentrantLock rlock = new ReentrantLock ();
rlock.lock();
try{
//dosth
}finally{
rlock.unlock();
}
ReentrantLock是排他锁,如果等待的条件没有被满足,就会持续等待,其它线程也会堵塞
ReentrantLock rlock = new ReentrantLock ();
rlock.lock();
try{
while(//线程堵塞的判断条件){
//wait
}
// dobusiness
}finally{
rlock.unlock();
}
ReentrantLock rlock = new ReentrantLock ();
Condition sufficientCondition = rlock.newCondition();
rlock.lock();
try{
while(true/*线程堵塞的判断条件*/){
//当前线程堵塞了,并且放弃了锁,可以使其它的线程获得锁
sufficientCondition.await();
}
// dobusiness
//其它的线程获得锁后,调用sufficientCondition的signalAll()方法,解除所有等待该条件的堵塞线程
//它们将尝试再次获得锁,但是只有其中的一个可以获得锁,并在堵塞的地方再次执行
//因此我们此处必须再次测试等待条件,
//如果调用signal方法很危险,因为唤醒的线程如果堵塞而没有调用signal方法就很容易使所有的线程
//等待下去,出现死锁
sufficientCondition.signalAll();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
rlock.unlock();
}
object的notify ()和notifyall()和wait()方法必须在持有当前锁的情况下才能使用否则会抛出 illegalmonitorstateexception异常
可以使用堵塞队列来实现
读写锁
使只读线程彼此之间不会堵塞
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
//运行只读线程可以共享访问
Lock readLock = rwl.readLock();
Lock writeLock = rwl.writeLock();
堵塞队列
java.util.concurrent.ArrayBlockingQueue<E> 循环数组实现
java.util.concurrent.LinkedBlockingQueue<E> 链表实现
java.util.concurrent.DelayQueue<E extends Delayed> 有限堵塞时间的堵塞队列
java.util.concurrent.PriorityBlockingQueue<E> 堆实现
线程安全的集合
高效队列和散列表
ConcurrentLinkedQueue和ConcurrentHashMap
可以稳定支持16个写入进程
ConcurrentLinkedQueue<E>
可以被多个线程安全访问的无边界的非堵塞队列
ConcurrentHashMap<K,V>
可以被多个线程安全访问的散列映射表
创建一个新线程的代价是很高的,因此使用线程池可以缓存一定数量的线程.
当线程的run方法退出时,线程不会死亡,而是在池中继续准备下一个请求提供服务.
但是线程池的应用并不是为了节省创建新线程的资源而是为了限制应用的线程数目.
首先没有必要为每个请求都创建线程,而且大量的线程会降低性能并且使虚拟机崩溃.