目录
1、并发队列
- 队列:先入先出
- 栈:先进后出
并发队列分为阻塞队列和非阻塞队列。
线程池就是阻塞队列实现的
1.1阻塞队列与非阻塞队列的区别
入队时:
非阻塞队列:当队列满了放入数据时,放不进去,数据丢失
阻塞队列:当队列满了放入数据时,等待队列中有数据出队时放入
出队时:
非阻塞队列:当队列为空取出数据是,取出为null
阻塞队列: 当队列为空取出数据是,等待队列中有数据进入再取出
1.2代码举例
1.2.1非阻塞队列——ConcurrentLinkedQueue
public static void main(String[] args) {
//无边界队列:没有限制队列长度
ConcurrentLinkedQueue<String> clq = new ConcurrentLinkedQueue<>();
clq.add("java");
clq.add("html");
clq.add("css");
//队列中元素的排列顺序:java,html,css
System.out.println(clq.poll()); //java
System.out.println(clq.size()); //2
System.out.println(clq.peek()); //html
System.out.println(clq.size()); //2 队列长度没有改变
}
队列的add()方法是往队列末尾插入元素
poll()和peek()方法
返回值都为String
poll():获取队首元素,并移除
peek():获取队首元素,但不移除
1.2.2阻塞队列——LinkedBlockingQueue
BlockingQueue是一个接口,它的实现类有:
LinkedBlockingQueue,ArrayBlockingQueue,DelayQueue,LinkedBlockingDeque,PriorityBlockQueue
使用add添加元素
public static void main(String[] args) {
BlockingQueue<String> bq = new LinkedBlockingQueue<>(3); //设置边界
//入队
bq.add("java");
bq.add("html");
bq.add("css");
bq.add("mysql");
//出队
System.out.println(bq.poll());
System.out.println(bq.poll());
System.out.println(bq.poll());
System.out.println(bq.poll());
/* Output:
* Exception in thread "main" java.lang.IllegalStateException: Queue full
* /
}
使用offer添加元素
bq.offer("java");
bq.offer("html");
bq.offer("css");
bq.offer("mysql");
/* Output:
* java html css null
* /
总结:
- add():在不违反容量限制的情况下立即将指定的元素插入此队列末尾,成功时返回true,如果当前没有可用空间,则抛出illeglastException。
- offer():在不违反容量限制的情况下立即将指定的元素插入此队列末尾,成功时返回true;如果当前没有可用空间,则返回false。
offer()还有一种添加方式,等待3秒后添加进队列
// Boolean offer(String e, long timeout, TimeUnit unit) 添加元素,等待时长,单位
bq.offer("mysql", 3, TimeUnit.SECONDS);
2、线程池
2.1什么是线程池?
一个正常的线程的生命周期是从创建到死亡(创建状态–>就绪状态–>运行状态–>死亡状态)
2.2ThreadPoolExecutor类
JDK1.5后引入了内置线程池的概念
2.2线程池的分类
可缓存线程池
public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool();
for(int i=0;i<=100;i++){
es.execute(new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
es.shutdown();
}
可缓存的线程池
* newCachedThreadPool
* 构造方法:new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,new SynchronousQueue());
* 可看成是无边界的线程池 最多能容纳(Integer的最大值)这么多线程
定长线程池
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(3); //核心线程数 = 最大线程数 = 3
for(int i=0;i<=100;i++){
es.execute(new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
es.shutdown();
}
定长的线程池
* newFixedThreadPool(int nThreads);
* 构造方法:new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue());
* 核心线程数=最大线程数=nThreads
定时线程池
public static void main(String[] args) {
ScheduledExecutorService ses = Executors.newScheduledThreadPool(3);//核心线程数
for(int i=0;i<100;i++){
ses.schedule(new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
},3, TimeUnit.SECONDS);
}
ses.shutdown();
}
定时线程池
* ScheduledThreadPoolExecutor extend ThreadPoolExecutors
* 传入参数=核心线程数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
单例线程池
public static void main(String[] args) {
ExecutorService es = Executors.newSingleThreadExecutor();
for(int i =0;i<=100;i++){
es.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
es.shutdown();
}
- 单例线程池
- newSingleThreadExecutor
- 当前线程池只有一个线程
- 核心线程=最大线程=1
- 构造方法 new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue()));