1:PV操作
PV操作由P操作和V操作组成,对信号量的操作,具体定义:
P(S):
1. 将信号量S的值减1,S=S-1
2. 如果S
≥
0,则该进程继续执行;否则进入等待状态,排入等待队列
V(S):
1.将i信号量S的值加1,S=S+1
2.如果S
>
0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。
2:java多线程
2.1 Thread和Runnable
java实现线程有两种方式,一种是自定义一个集成自Thread的类,重写run函数;还有一种是直接实现Runnable接口。
其实本质上这两种方式都是提供一个run函数给线程调用。我们看一下Thread的源码。
public Thread(Runnable target) {
//此处可以看出是将我们传入的runnable对象赋给Thread的target对象
init(null, target, "Thread-" + nextThreadNum(), 0);
}
//此处的run函数提供给线程调用
public void run() {
//这里判断有没有target对象,如果有说明我们传入调用了Thread(Runnable)构造函数,此处实际即调用了我们重写的Runnable接口的run函数。
if (target != null) {
target.run();
}
}
//如果我们自定义的类继承了Thread类,并且重写了run函数,那么我们实际给线程调用的函数即是我们重写的run函数。
2.2 线程池相关类
ThreadPoolExecutor的具体介绍可以看这篇博客
http://www.cnblogs.com/dolphin0520/p/3932921.html
ThreadPoolExecutor
我们先看两张图
- 任务执行流程图
- 任务队列图
几个关键点 - corePoolSize 核心线程池大小,线程池刚启动时来一个任务就会创建一个线程去执行这个任务,直到达到corePoolSize个线程,这时再来的任务就会加到任务队列中去,直到任务队列满了,这时会尝试创建新的线程,但是总线程数量必须少于maximumPoolSize,如果线程也不能创建了,这时就会拒绝执行任务了。
- maximumPoolSize 最大线程数,线程池总线程数量不得多于maximumPoolSize
- keepAliveTime 线程存货时间,主要是在最大线程数到核心线程数之间的线程存活时间,比如corePoolSize = 10,maximumPoolSize =100。当线程池达到100时,这时每个线程不执行且过了keepAliveTime 的时间后就会消失,但是当线程池数量到达corePoolSize 线程不在消失。也就是说keepAliveTime 不起作用了。
- Queue任务队列 有三种类型(无限队列、直接队列、有限队列)
直接队列来一个任务会直接尝试创建新线程执行。
无限队列会当线程池数量达到corePoolSize 时新来的任务都会加入队列中,这时maximumPoolSize 就不起作用了。
有限队列在线程达到corePoolSize 且任务队列已满时来一个任务会尝试继续创建线程,知道达到maximumPoolSize
Executors是创建线程池的工厂类。提供了以下几个主要方法
- newCachedThreadPool函数
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
可以看出创建了一个核心线程数为0,最大线程数为一个Integer能表示的最大值,存活时间为60秒。队列为SynchronousQueue直接队列。这种情况下每来一个任务就创建一个线程执行。直到创建的线程数大于Integer.MAX_VALUE当然一般情况下不会出现。每一个线程的存货时间是60秒超过60秒后自动销毁。
- newFixedThreadPool函数
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
可以看出创建了一个核心线程数为传入的nThreads,最大线程数也为nThreads,存活时间为0秒。队列为LinkedBlockingQueue即不保存队列任务。这种情况下每来一个任务首先看线程池数量有没有到nThreads,如果没有达到则创建一个新的线程并执行,否则加入队列中,等待执行。此处LinkedBlockingQueue没有指定大小即最多可以接收Integer.MAX_VALUE个缓冲任务。相当于创建了nThreads个线程来执行队列中的任务。
- newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
和上面的newFixedThreadPool类似,只不过这里只有一个线程,即使用一个线程执行任务队列中的任务。