线程池概念
• 现有问题:
• 线程是宝贵的内存资源、单个线程约占 1MB 空间,过多分配易造成内存溢出。
• 频繁的创建及销毁 线程 会增加虚拟机回收频率、资源开销,造成程序性能下降。
• 线程池:
• 线程容器,可设定线程分配的数量上限。
• 将预先创建线程对象存入池中,并重用线程池中的线程对象。
• 避免频繁的创建和销毁。
• 将任务提交给线程池,由线程池分配线程、运行任务,并在当前任务结束后复用线程。
获取线程池
• 常用的线程池接口和类( ( 所在包 java.util.concurrent) :
• Executor :线程池的顶级接口。
• ExecutorService :线程池接口,可通过 submit(Runnable task) 提交任务代码。
• Executors 工厂类:通过此类可以获得一个线程池。
• 通过 newFixedThreadPool(int nThreads) 获取固定数量的线程池。参数:指定线
程池中线程的数量。
• 通过 newCachedThreadPool() 获得动态数量的线程池,如不够则创建新的,没有上限.
Callable接口
public interface Callable<V> {
public V call() throws Exception;
}
• JDK5 加入,与 Runnable 接口类似,实现之后代表一个线程任务。
• Callable 具有泛型返回值、可以声明异常。
Future接口
• Future 概念:异步计算的结果, ExecutorService.submit() 所返回的状态
结果,当中包含了 call() 的返回值
• 方法: V get() : 以阻塞形式等待 Future 中的异步处理结果( call() 的返回值)
线程的同步
` 同步:
` 形容一次方法调用,同步一旦开始,调用者必须等待该方法返回,才能继续.(单条执行路径)
线程的异步
` 异步:
` 形容一次方法的调用,异步一旦开始,像是一次消息传递,调用者告知之后立刻返回.二者竞争时间片,并发执行.(多条路径).
Lock接口
• JDK5 加入,与 synchronized 比较,显示定义,结构更灵活。
• 提供更多实用性方法,功能更强大、 性能更优越 。
• 常用方法: :
void lock() // 获取锁,如锁被占用,则等待。
boolean tryLock() // 尝试获取锁(成功返回 true 。 失败 返回 false ,不阻塞)
void unlock() //
重入锁:ReentrantLock : Lock 接口的实现类,与 synchronized 一样具有互斥锁功能。
class MyList{
private Lock locker = new ReentrantLock(); //创建重入锁对象
private String[] strs = {"A","B","C"," "};
private int count = 2; //元素个数
//添加元素
public void add(String value){
locker.lock(); //显示开启锁
try{
strs[count] = value;
try{
Thread.sleep(1000); //主动休息1秒钟
} catch (InterruptedException e) {}
count++;
}finally{
locker.unlock(); //显示释放锁
}
}
}
读写锁:
• ReentrantReadWriteLock :
• 一种支持一写多读的同步锁,读写分离,可分别分配读锁、写锁。
• 支持多次分配读锁,使多个读操作可以并发执行.
• 互斥规则:
• 写- - 写:互斥,阻塞 。
• 读- - 写:互斥,读阻塞写、写阻塞读。
• 读- - 读:不互斥、不阻塞 。
• 在读操作远远高于写操作的环境中,可在保障线程安全的情况下,提高运行效率。
Collections中的工具方法
• Collections 工具类中提供了多个可以获得线程安全集合的方法。
• public static <T> Collection<T> synchronizedCollection(Collection<T> c)
• public static <T> List<T> synchronizedList(List<T> list)
• public static <T> Set<T> synchronizedSet(Set<T> s)
• public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
• public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s)
• public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
• JDK1.2 提供,接口统一、维护性高,但性能没有提升,均以 synchonized 实现。
CopyOnWriteArrayList
• 线程安全的 ArrayList ,加强版读写分离。
• 写有锁,读无锁,读写之间不阻塞,优于读写锁。
• 写入时,先 copy 一个容器副本、再添加新元素, 最后 替换引用。
• 使用方式与 ArrayList 无异。
public class TestCopyOnWriteArrayList{
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<String>();
}
}
ConcurrentHashMap
• 初始容量默认为 16 段( Segment ),使用分段锁设计。
• 不对整个 Map 加锁,而是为每个 Segment 加锁。
• 当多个对象存入同一个 Segment 时,才需要互斥。
• 最理想状态为 16 个对象分别存入 16 个 Segment ,并行数量 16 。
• 使用方式与 HashMap 无异。
public class TestCopyOnWriteArrayList{
public static void main(String[] args) {
Map<Stirng,String> map = new ConcurrentHashMap<Stirng,String>();
}
}
Queue接口(队列)
• Collection 的子接口,表示队列 FIFO ( First In First Out )
• 常用方法:
• 抛出异常:
• boolean add(E e) // 顺序添加一个元素(到达上限后,再添加则会抛出异常)
• E remove() // 获得第一个元素并移除(如果队列没有元素时,则抛异常)
• E element() // 获得第一个元素但不移除(如果队列没有元素时,则抛异常)
• 返回特殊值: 推荐使用
• boolean offer(E e) // 顺序添加一个元素 (到达上限后,再添加则会返回 false )
• E poll() // 获得第一个元素并移除 (如果队列没有元素时,则返回 null )
• E keep() // 获得第一个元素但不移除 (如果队列没有元素时,则返回 null )
public class TestCopyOnWriteArrayList{
public static void main(String[] args) {
Queue<Stirng> queue = new ConcurrentLinkedQueue<String>();
queue.offer("Hello"); //插入
queue.offer("World"); //插入
queue.poll(); //删除Helllo
queue.peek(); //获得World
}
}
BlockingQueue接口(阻塞队列)
• Queue 的子接口,阻塞的队列,增加了两个线程状态为无限期 等待的方法 。
• 方法:
• void put(E e) // 将指定元素插入此队列中 ,如果没有可用空间,则等待。
• E take() // 获取并移除此队列头部元素,如果没有可用元素,则等待.
• 可用于解决生产生、消费者问题。
阻塞队列
• ArrayBlockingQueue :
数组结构实现,有界队列。(手工固定上限)
public class TestCopyOnWriteArrayList{
public static void main(String[] args) {
BlockingQueue<String> abq = new ArrayBlockingQueue<String>(10);
}
}
• LinkedBlockingQueue :
链表结构实现,无界队列。(默认上限 Integer.MAX_VALUE )
public class TestCopyOnWriteArrayList{
public static void main(String[] args) {
BlockingQueue<Stirng> lbq = new LinkedBlockingQueue<String>();
}
}