jdk1.5后,提供了java.util.concurrent包,它可以实现线程池,你把线程当成普通对象就可以了,它来负责调度和执行
包括两类线程池
固定线程池
可变线程池
延迟线程池
固定线程池
public static ExecutorService newFixedThreadPool(int nThreads) 多任务
public static ExecutorService newSingleThreadPool() 单任务
ExecutorService 的方法
Excute(Runnablecommand);
shutdown();
用法如下
Mytask mt1=new Mytask("T1");//一个线程对象实例
ExecutorService threadpool=Executors.newFixedThreadPool(2);
threadpool.excute(mt1);
可变线程池
public static ExecutorService newCachedThreadPool()
延迟线程池,实现定时任务
public static ScheduledExecutorService newScheduledThreadPool(int poolSize)
它不使用excute方法了,而是使用schedule方法
public SchedualedFuture schedule(Runnable command,long delay,TimeUnit unit);
有返回值的线程池
Callable接口配合Future接口,Future接口用来接受返回值
Callable接口作用同runnable接口,不过它是实现call接口方法,这个方法还有返回值
class myCallableImpl implements Callable
{
public Object call()
{
}
}
使用
ExecutorService threadpool =Executors.newSingleThreadExector();
Future f=threadpool.submit(new myCallableImpl();
资源封锁
前面我们知道syncnized方法可以对一段代码进行资源封锁,实际上还有很多其他方法,这里总结一下
1:synchronized
2:变量volatile
3:lock接口的实现 ReentrantLock类,它有方法:lock()、unlock(),tryLock()等,注意要try……finally,防止死锁
4:ReadWriteLock接口实现 ReentrantReadWriteLock类,方法为readLock,writeLock,使用方法大致同lock接口,不过它的效率高。也要防止死锁
5:信号量 Semaphore类,信号量不同于锁,是用来实现资源分配的,但是也有锁的特性,比如连接池,保证连接池不爆炸就可以使用这个类,主要方法为:acquire(),acquire(int n),tryAcquire(),getQueueLength(),release()
6:原子对象,在jdk15后,为了简化操作,可以把一些基本类型定义为原子对象,就单线程操作了。java.util.concurrent.atomic ,作用基本同变量volatile
7:障碍器,CyclicBarrier类,让线程同步到同一个点
队列和堆栈
java.util.Queue接口
public boolean offer(Object); 加入
public Object poll(); 出
peek(); 出,但是不删除
remove();同poll
element();同peek
add();同offer
常见实现为:java.util.LinkedList 和 java.util.PriorityQueue
BlockingQueue接口
java.util.concurrent.BlockingQueue
put(Object);进
take();出
BlockingDeque接口
它是一个阻塞的堆栈接口
putFirst(object o);
takeFirst();
putLast();
takeLast();
ReentrantReadWriteLock介绍
在java中提供了ReentrantReadWriteLock类 ,并可抽取读锁和写锁。读锁可以被多个读操作共享,并且会排斥所有写操作;写锁则互斥所有写操作和读操作。
使用读/写锁的必要步骤:
class RWDictionary {
private final Map m = new TreeMap();
//1)创建ReentrantReadWriteLock对象
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();//2) 抽取读锁
private final Lock w = rwl.writeLock();//2) 抽取写锁
public Data get(String key) {
3) 对所有读者加锁
r.lock(); try { return m.get(key); } finally { r.unlock(); }
}
public String[] allKeys() {
3 ) 对所有读者加锁
r.lock(); try { return m.keySet().toArray(); } finally { r.unlock(); }
}
public Data put(String key, Data value) {
4) 对所有写者加锁:
w.lock(); try { return m.put(key, value); } finally { w.unlock(); }
}
public void clear() {
4) 对所有写者加锁:
w.lock(); try { m.clear(); } finally { w.unlock(); }
}
}
这样可以保证 a) 写者之间以及写者和读者之间互斥
b) 同一时间只有一个写者写,多个读者可以同时读
这样读者和写者的优先级相同,当有大量的读者和极少的写者时,写进程可能很难得到执行。所以当需要写操作优先级更高时可以设置ReentrantReadWriteLock 的策略,设置为非公平策略即可
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(false);
把构做ReentrantReadWriteLock设为false(非公平策略)(默认为true)
公平策略:当公平地构造线程时,线程利用一个近似到达顺序的策略来争夺进入。当释放写入锁定后,将写入锁定分配给等待时间最长的单个写入者,如果有一个等待时间比所有写入者更长的读取者,则将读取锁定分配给读取者
非公平策略:当非公平地构造线程时,则不需要按照到达顺序进入锁定。不管是哪一种情况,如果读取者处于活动状态,而某个写入者进入锁定状态,那么在获取写入者并释放写入锁定之前,不会将读取锁定授予任何后续的读取者。