摘要
本文主要简单讲解了Java多线程之中的线程间通信机制和几个简单的多线程应用实例
1 参考资料
- Java并发编程艺术第四章
- https://www.cnblogs.com/xudilei/p/6867045.html
2 基本方式和等待/通知的经典范式
首先指出,Java中线程的通信是基于共享内存来实现的!
即各个线程去读写该共享内存中的内容从而达到通信的效果。
- volatile关键字和sychronized关键字
- wait和notify
关键字volatile可以用来修饰字段(成员变量),就是告知程序任何对该变量的访问均需要从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性。
volatile和synchronized 底层解析,可以瞅瞅
关键字synchronized可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性。
等待和通知机制
(下面举了一个不辣么恰当的栗子)
讲述这个问题最经典的立即还是生产者消费者问题。(真的是经典,感觉都快用烂了,所以我决定换个例子)
假设哈,这里有两个线程和一个共享内存区域
共享内存区域----一个秘密根据地
线程A----特工A
线程B----特工B
一天,特工A想要跟特工B通信,因为他发现了一个天大的秘密,但是他们的通信已经被敌方监控,他只能去秘密根据地留下信息。
特工A走进秘密根据地后,反锁了门(锁的概念),然后留下了信息。然后离开,等待特工B的回信(调用了wait)。
特工B之后前往根据地,获取了信息后,想办法给了特工A一个信号(notify)
于是乎,通信完成。
然后回归正经,我们来看下wait和notify方法的详细描述。需要在意的是,调用wait方法时,会释放对象的锁
调用wait和notify时,需要用synchronized锁住,确保代码段不会被多个线程调用。
下面是一张描述等待和通知的转移图,东西都在里面了(微笑脸)
等待/通知的经典范式
等待方:
1)获取对象的锁
2)如果条件不满足,调用wait,被通知后仍要检查条件
3)条件满足则执行相应逻辑
synchronized( object ){
while(condition){
object.wait()
}
doSomething()
}
通知方:
1)获取对象锁
2)改变条件
3)通知所有等待在该对象上的线程
synchronized( object ){
change condition
object.notifyAll()
}
3 等待超时的介绍
再套用下上面特工的例子(虽然举得不是很吼),话说特工A留下信息后(wait),要是特工B突然暴露被抓(线程终止)怎么办?难道一直等下去么?
不,当然不会,优秀的特工往往都有计划A和计划B,特工A的A计划自然就是B收到信息后两人一起行动。如果迟迟收不到特工B的回信,那么只好执行计划B了。(意思就是线程A wait 一段时间后不等了,开始做自己该做的事 )
关于超时等待的使用,就是重载了wait和notify方法,加入了一个时间参数,超出该时间后,挂起的线程会自动恢复,然后继续执行。
4 应用-简单线程池
线程池的本质就是使用了一个线程安全的工作队列连接工作者线程和客户端线程,客户端线程将任务放入工作队列后返回,而工作线程则不断地从工作队列中取出工作并且执行。
线程池接口
package threadpool;
//线程池接口
public interface ThreadPool<Job extends Runnable> {
void execute(Job job);
void shutdowm();
void addWorkers(int num);
void removeWorkers(int num);
int getJobSize();
}
线程池实现
package threadpool;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
public class DefaultThreadPool<Job extends Runnable> implements ThreadPool<Job> {
private static final int MAX_WORKER_NUMBERS = 10;
private static final int DEFAULT_WORKER_NUMBERS = 5;
private static final int MIN_WORKER_NUMBERS = 1;
private final LinkedList<Job> jobs = new LinkedList<Job>();
private final List<Worker> workers = Collections.synchronizedList(new ArrayList<Worker>());
private int workNum = DEFAULT_WORKER_NUMBERS;
//线程编号
private AtomicLong threadNum = new AtomicLong();
public DefaultThreadPool(int num){
workNum = num > MAX_WORKER_NUMBERS ? MAX_WORKER_NUMBERS : num < MAX_WORKER_NUMBERS ? MIN_WORKER_NUMBERS:num;
initializeWorkers(workNum);
}
private void initializeWorkers(int num){
for(int i=0;i<num;i++){
Worker worker = new Worker();
workers.add(worker);
// 初始化线程工作者,放入工作列表
Thread thread = new Thread(worker,"Thread-worker-"+threadNum.incrementAndGet());
thread.start();
}
}
@Override
public void execute(Job job) {
synchronized (jobs){
if(job!=null){
jobs.addLast(job);
jobs.notify();
}
}
}
@Override
public void shutdowm() {
for( Worker worker : workers){
worker.shutdown();
}
}
@Override
public void addWorkers(int num) {
synchronized (jobs){
if(num + this.workNum > MAX_WORKER_NUMBERS ){
num = MAX_WORKER_NUMBERS - this.workNum;
}
initializeWorkers(num);
this.workNum +=num;
}
}
@Override
public void removeWorkers(int num) {
synchronized (jobs){
if( num >= this.workNum ){
throw new IllegalArgumentException("beyond workNum");
}
//按照给定的num 停止worker
int count = 0;
while (count < num ){
Worker worker = workers.get(count);
if(workers.remove(worker)){
worker.shutdown();
count++;
}
}
this.workNum -= count;
}
}
@Override
public int getJobSize() {
return jobs.size();
}
// 工作线程
class Worker implements Runnable {
// 标志位 是否工作
private volatile boolean running = true;
@Override
public void run() {
while (running){
Job job = null;
synchronized (jobs){
//如果工作列表为空 就wait
while (jobs.isEmpty()){
try {
jobs.wait();
}catch (InterruptedException e){
// 感知到外部对WorkerThread的中断操作,返回
Thread.currentThread().interrupt();
return;
}
}
job = jobs.removeFirst();
}
if(job!=null){
try {
job.run();
}catch (Exception ex){
}
}
}
}
public void shutdown(){
running = false;
}
}
}
class Job implements Runnable{
@Override
public void run() {
System.out.println("该Job的任务是打印下当前时间,然后休眠1s");
System.out.println(new Date());
try{
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
测试类
package threadpool;
public class test {
public static void main(String[] args) {
DefaultThreadPool threadPool = new DefaultThreadPool(10);
threadPool.removeWorkers(2);
threadPool.addWorkers(3);
for(int i = 0; i< 100 ; i++){
Thread t = new Thread(new Job(),"job-"+i);
threadPool.execute(t);
}
threadPool.shutdowm();
}
}
结果: