一、ThreadPoolExecutor 线程池执行者
- 初始化线程池的参数
corePoolSize | 核心线程大小 |
maximumPoolSize | 最大线程大小 |
keepAliveTime | 空余的多余线程保持时间 |
unit | 时间单位 |
workQueue | 阻塞队列 |
handler | 拒绝服务助手 |
- 线程池内部运行机制
1、当有任务委托给线程池,若池中线程数量 < 核心线程数量,则创建新的线程,即使有空闲线程。
2、若核心线程数量已满,且没有空闲,则把任务放入阻塞队列。
3、若核心线程和阻塞队列都没有空闲,此时再来任务,则判断当前池内线程数量是否 < 最大线程数量。若小于则创建临时线程去处理该任务。
4、若核心线程,阻塞队列,临时线程都已经到达上限,且被占用。此时再来任务,则由拒绝助手去处理。
- 代码示例
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorDemo {
public static void main(String[] args) throws InterruptedException {
//阻塞队列
ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(2);
//拒绝助手
RejectedExecutionHandler handler = new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("线程池已满 ##### 任务被拒绝 ");
}
};
//创建线程池
ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS, workQueue, handler);
//1,2被核心线程处理
pool.execute(new RunnableDemo(1,5000L));
pool.execute(new RunnableDemo(2,5000L));
Thread.sleep(100);
//3,4放入阻塞队列,等核心线程或临时线程有空闲了再处理
pool.execute(new RunnableDemo(3,2000L));
pool.execute(new RunnableDemo(4,2000L));
Thread.sleep(100);
//5,6被临时线程处理
pool.execute(new RunnableDemo(5,2000L));
pool.execute(new RunnableDemo(6,2000L));
Thread.sleep(100);
//7,8被拒接助手处理了
pool.execute(new RunnableDemo(7,2000L));
pool.execute(new RunnableDemo(8,2000L));
//线程池关闭
pool.shutdown();
}
}
class RunnableDemo implements Runnable {
private int id;
private long time;
public RunnableDemo(int id, long time) {
this.id = id;
this.time = time;
}
@Override
public void run() {
try {
System.out.println("id=" + id + " 开始执行!时间:" + System.currentTimeMillis());
Thread.sleep(time);
System.out.println("id=" + id + " 执行完成!时间:" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
二、ExecutorService 执行器服务
- 获取线程池
通过Executors类的各个静态方法,可以直接获取常用配置的线程池。
例如:
ExecutorService executorService = Executors.newFixedThreadPool(5);
其实内部也是用ThreadPoolExecutor来实现:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
- 执行
execute(Runnable) | 没有返回结果 |
submit(Runnable) | 返回值类型为 Future,可以通过Future的get()方法来观察任务是否执行结束。若没结束,则该方法会阻塞。 |
submit(Callable) | 与submit(Runnable)类似,唯一区别是submit(Callable) 还可以通过get() 方法获取返回结果。 |
invokeAny() | 入参为一个Callable或其子接口实例对象的集合,如果其中一个任务执行完成或者异常,其他的Callable将被取消。并返回其中一个Callable的执行结果。 |
invokeAll() | 入参为一个Callable或其子接口实例对象的集合,执行所有任务,并返回一个Future对象的集合。但是无法通过Future知道任务是正常结束还是执行异常。 |
- 关闭线程池
shutdown() | 执行后则不再接受任务,直到任务执行完成才关闭 |
shutdownNow() | 立即关闭 |
- 代码示例
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ExecutorServiceDemo {
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(5);
Future<String> future = executorService.submit(new CallableDemo());
//阻塞直到任务结束
System.out.println(future.get());
executorService.shutdown();
}
}
class CallableDemo implements Callable<String> {
public String call() throws Exception {
System.out.println("开始执行!");
Thread.sleep(3000);
System.out.println("执行结束!");
return "china@!";
}
}
三、Lock锁
作用类似synchronized,但是更灵活,通过lock(),unlock()两个方法配合使用,保证线程安全。
lock() | 将 Lock 实例锁定 |
lockInterruptibly() | lockInterruptibly() 方法将会被调用线程锁定,除非该线程被打断。此外,如果一个线程在通过这个方法来锁定 Lock 对象时进入阻塞等待,而它被打断了的话,该线程将会退出这个方法调用。 |
tryLock() | 试图立即锁定 Lock 实例。并返回成功结果,永不阻塞 |
unlock | 对 Lock 实例解锁 |
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockDemo {
public static void main(String[] args) throws InterruptedException {
Lock lock = new ReentrantLock();
Thread t1 = new Thread(new T1(lock));
Thread t3 = new Thread(new T1(lock));
t1.start();
Thread.sleep(100);
t3.start();
t3.interrupt();
}
}
class T1 implements Runnable {
Lock lock = null;
public T1(Lock lock) {
this.lock = lock;
}
public void run() {
try {
//当当前执行线程被打断时,当前线程会退出这个方法调用
lock.lockInterruptibly();
System.out.println("任务开始执行!");
Thread.sleep(2000);
System.out.println("任务执行结束!");
} catch (Exception e) {
System.out.println("线程被打断");
}finally {
lock.unlock();
}
}
}
四、ReadWriteLock读写锁
读是可以并发处理的,但是读和写,或者多个写是不可以并发处理的。
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockDemo {
public static String name = "lisi";
public static void main(String[] args) {
ReadWriteLock lock = new ReentrantReadWriteLock();
//read可以并发
new Thread(new TRead(lock)).start();
new Thread(new TRead(lock)).start();
new Thread(new TRead(lock)).start();
//read+write 或者 多个write不能并发
new Thread(new TWrite(lock)).start();
new Thread(new TWrite(lock)).start();
new Thread(new TRead(lock)).start();
}
}
class TWrite implements Runnable {
private ReadWriteLock lock = null;
public TWrite(ReadWriteLock lock) {
this.lock = lock;
}
public void run() {
try {
lock.writeLock().lock();
System.out.println(Thread.currentThread().getId() + " # 开始写数据");
Thread.sleep(2000);
ReadWriteLockDemo.name ="wangwu";
System.out.println(Thread.currentThread().getId() + " # 数据写入成功" + ReadWriteLockDemo.name);
lock.writeLock().unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class TRead implements Runnable {
private ReadWriteLock lock = null;
public TRead(ReadWriteLock lock) {
this.lock = lock;
}
public void run() {
try {
lock.readLock().lock();
System.out.println(Thread.currentThread().getId() + " # 开始读数据");
Thread.sleep(2000);
ReadWriteLockDemo.name ="wangwu";
System.out.println(Thread.currentThread().getId() + " # 读取到数据" + ReadWriteLockDemo.name);
lock.readLock().unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}