写在开篇的几句话
线程并发库即java.util.concurrent包以及其下面的子包。始于JDK1.5,作者是Doug Lea.
本篇文章主要通过一个案例的实现代码记录线程并发库的部分操作使用,可能囊括的内容不是很全面,请各位见谅,如有错误,欢迎指正!
案例需求说明
想象这样一个业务场景,有一个业务,分为三个部分,其中每个部分都必须是满足原子操作,即执行过程不可被同一个程序中的其他线程中断。将这个业务映射为一个Java类,每个部分对应类中的一个具体方法,现在要求,这些方法轮流依次执行,其中任务1先执行,紧接着任务2执行,再接着任务3执行,再接着任务1执行,如此顺序依次轮流50遍,同时要求由三个线程分别执行这三个任务中的一个。其中每个任务中的代码可以是简单的执行一个循环,如循环10次,打印相关的线程以及运行状态信息,对应到具体现实场景,可以做相应的改动即可。
为了实现上面的这个需求,需要深刻认识到,这个业务需要保证每个任务的原子性,即需要保证自身的线程安全性,同时任务之间需要通信。
这里采用Java锁机制和条件变量实现,需要记住,条件变量Condition是依附于具体的锁而存在的,一个锁关联多个依附于它的条件变量,每个条件变量用于协调与该锁相关的若干线程之间的一种通信,即某个线程在某个情况下等待某个条件变量的成立,而这个条件变量是由另外一个线程在某种情况下使之成立的。对应到Java代码下就是condition.await() 和 condition.signal(),前者用于线程阻塞等待条件成立,后者用于通知等待此条件的阻塞线程恢复至就绪状态,准备接收CPU调度。
需要时刻清楚,condition是依附于lock存在的,就好比Object底下的wait和notify方法必须依附于某个同步监视器对象存在的,即wait和notify必须用于同步代码块或同步方法里,且调用wait和notify的对象必须是同步代码块和同步方法上的同步监视器对象。往底层深入一下,其实在调用condition.await()方法进入阻塞状态之前,线程会释放已经获取到的与该condition有关的锁,从而使得竞争该锁的其它线程的获得该锁,然后这个获得锁的线程,继续运行,当它执行完了自己的原子操作时,condition.notify(),唤醒刚刚阻塞于该条件的线程,此时该线程不会立马失去锁,而是继续执行同步代码,直到lock.unlock()。而被唤醒的线程,则会去尝试获得锁,下面的案例代码中,被唤醒的线程是在唤醒它的那个线程执行完lock.unlock()之后才获得锁继续向下执行的。
废话不多说直接上代码
package com.ilovecoding.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadTest12 {
public static void main(String[] args) {
BusinessNew businessNew = new BusinessNew();
ExecutorService threadPool = Executors.newFixedThreadPool(3);
threadPool.execute(() -> {
for (int i = 1; i <= 50; i++) {
businessNew.task1(i);
}
});
threadPool.execute(() -> {
for (int i = 1; i <= 50; i++) {
businessNew.task2(i);
}
});
threadPool.execute(() -> {
for (int i = 1; i <= 50; i++) {
businessNew.task3(i);
}
});
}
}
class BusinessNew {
private Lock lock = new ReentrantLock();
private Condition cond1 = lock.newCondition();
private Condition cond2 = lock.newCondition();
private Condition cond3 = lock.newCondition();
private int flag = 1;
public void task1(int i) {
lock.lock();
try {
while (flag != 1) {
try {
cond1.await(); // 等待cond1这个条件通知
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int j = 1; j <= 10; j++) {
System.out.println(Thread.currentThread().getName() + " sequence " + j + " of loop " + i);
}
flag = 2;
cond2.signal();
} finally {
lock.unlock();
}
}
public void task2(int i) {
lock.lock();
try {
while (flag != 2) {
try {
cond2.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int j = 1; j <= 10; j++) {
System.out.println(Thread.currentThread().getName() + " sequence " + j + " of loop " + i);
}
flag = 3;
cond3.signal();
} finally {
lock.unlock();
}
}
public void task3(int i) {
lock.lock();
try {
while (flag != 3) {
try {
cond3.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int j = 1; j <= 10; j++) {
System.out.println(Thread.currentThread().getName() + " sequence " + j + " of loop " + i);
}
flag = 1;
cond1.signal();
} finally {
lock.unlock();
}
}
}
运行的部分结果
pool-1-thread-1 sequence 1 of loop 1
pool-1-thread-1 sequence 2 of loop 1
pool-1-thread-1 sequence 3 of loop 1
pool-1-thread-1 sequence 4 of loop 1
pool-1-thread-1 sequence 5 of loop 1
pool-1-thread-1 sequence 6 of loop 1
pool-1-thread-1 sequence 7 of loop 1
pool-1-thread-1 sequence 8 of loop 1
pool-1-thread-1 sequence 9 of loop 1
pool-1-thread-1 sequence 10 of loop 1
pool-1-thread-2 sequence 1 of loop 1
pool-1-thread-2 sequence 2 of loop 1
pool-1-thread-2 sequence 3 of loop 1
pool-1-thread-2 sequence 4 of loop 1
pool-1-thread-2 sequence 5 of loop 1
pool-1-thread-2 sequence 6 of loop 1
pool-1-thread-2 sequence 7 of loop 1
pool-1-thread-2 sequence 8 of loop 1
pool-1-thread-2 sequence 9 of loop 1
pool-1-thread-2 sequence 10 of loop 1
pool-1-thread-3 sequence 1 of loop 1
pool-1-thread-3 sequence 2 of loop 1
pool-1-thread-3 sequence 3 of loop 1
pool-1-thread-3 sequence 4 of loop 1
pool-1-thread-3 sequence 5 of loop 1
pool-1-thread-3 sequence 6 of loop 1
pool-1-thread-3 sequence 7 of loop 1
pool-1-thread-3 sequence 8 of loop 1
pool-1-thread-3 sequence 9 of loop 1
pool-1-thread-3 sequence 10 of loop 1
pool-1-thread-1 sequence 1 of loop 2
pool-1-thread-1 sequence 2 of loop 2
pool-1-thread-1 sequence 3 of loop 2
pool-1-thread-1 sequence 4 of loop 2
pool-1-thread-1 sequence 5 of loop 2
pool-1-thread-1 sequence 6 of loop 2
pool-1-thread-1 sequence 7 of loop 2
pool-1-thread-1 sequence 8 of loop 2
pool-1-thread-1 sequence 9 of loop 2
pool-1-thread-1 sequence 10 of loop 2
pool-1-thread-2 sequence 1 of loop 2
pool-1-thread-2 sequence 2 of loop 2
pool-1-thread-2 sequence 3 of loop 2
pool-1-thread-2 sequence 4 of loop 2
pool-1-thread-2 sequence 5 of loop 2
pool-1-thread-2 sequence 6 of loop 2
pool-1-thread-2 sequence 7 of loop 2
pool-1-thread-2 sequence 8 of loop 2
pool-1-thread-2 sequence 9 of loop 2
pool-1-thread-2 sequence 10 of loop 2
pool-1-thread-3 sequence 1 of loop 2
pool-1-thread-3 sequence 2 of loop 2
pool-1-thread-3 sequence 3 of loop 2
pool-1-thread-3 sequence 4 of loop 2
pool-1-thread-3 sequence 5 of loop 2
pool-1-thread-3 sequence 6 of loop 2
pool-1-thread-3 sequence 7 of loop 2
pool-1-thread-3 sequence 8 of loop 2
pool-1-thread-3 sequence 9 of loop 2
pool-1-thread-3 sequence 10 of loop 2
pool-1-thread-1 sequence 1 of loop 3