目录
为什么要线程通讯
多个线程并发执行时,在默认情况下CPU是随机切换线程的,有事我们希望CPU按照我们的规律去执行线程,此时就需要线程之间的协调通讯。
常用方法
休眠唤醒方式:
Object
- wait()
- notify()
- notifyAll()
示例代码:
public class OddEven {
private int num = 0;
Object object = new Object();
public synchronized void Odd(){
while (num < 10){
synchronized (object){
if (num%2 == 1){
System.out.println("奇数:"+ num);
num++;
object.notify();
}else {
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public void Even(){
while (num < 10){
synchronized (object){
if (num%2 == 0){
System.out.println("偶数:" + num);
num++;
object.notify();
}else {
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
final OddEven oddEven = new OddEven();
new Thread(()->{
oddEven.Even();
}).start();
new Thread(()->{
oddEven.Odd();
}).start();
}
}
运行结果:
Condition
- await()
- signal()
- signalAll()
实例代码:
public class OddEven1 {
private int num = 0;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public synchronized void Odd(){
while (num < 10){
lock.lock();
try {
if (num%2 == 1){
System.out.println("奇数:"+ num);
num++;
condition.signal();
}else {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}finally {
lock.unlock();
}
}
}
public void Even(){
while (num < 10){
lock.lock();
try {
if (num%2 == 0){
System.out.println("偶数:"+ num);
num++;
condition.signal();
}else {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
final OddEven oddEven = new OddEven();
new Thread(()->{
oddEven.Even();
}).start();
new Thread(()->{
oddEven.Odd();
}).start();
}
}
运行结果:
补充:
- Object的wait()方法必须再synchronized(同步锁下使用)
- Condition的await()方法必须和Lock(互斥锁/共享锁)配合使用
CountDownLatch
- countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。
- 是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。
演示代码:
package communication;
import java.util.concurrent.CountDownLatch;
public class CoachRacer {
private CountDownLatch countDownLatch = new CountDownLatch(3);
//教练方法
private void Coach(){
System.out.println(Thread.currentThread().getName()+" 教练正在准备。。。");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 教练开始教练");
}
//运动员方法
private void Racer(){
System.out.println(Thread.currentThread().getName()+" 运动员正在准备。。。");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 运动员准备完成");
countDownLatch.countDown();
}
public static void main(String[] args) {
final CoachRacer coachRacer = new CoachRacer();
new Thread(()->{
coachRacer.Coach();
},"教练").start();
new Thread(()->{
coachRacer.Racer();
},"运动员1").start();
new Thread(()->{
coachRacer.Racer();
},"运动员2").start();
new Thread(()->{
coachRacer.Racer();
},"运动员3").start();
}
}
运行结果:
CyclicBarrier
一组线程等待至某个状态之后再全部同时执行
示例代码:
public class ThreeThreadStar {
private CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
public void startThread(){
System.out.println(Thread.currentThread().getName()+" 启动");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("线程启动:"+System.currentTimeMillis());
}
public static void main(String[] args) {
final ThreeThreadStar threeThreadStar = new ThreeThreadStar();
new Thread(()->{
threeThreadStar.startThread();
},"线程1").start();
new Thread(()->{
threeThreadStar.startThread();
},"线程2").start();
new Thread(()->{
threeThreadStar.startThread();
},"线程3").start();
}
}
运行结果:
Semaphore
用于控制对某组资源的访问权限
示例代码:
package communication;
import java.util.concurrent.Semaphore;
public class WorkerMachine {
static class Work implements Runnable{
private int workerNum;
private Semaphore semaphore;
public Work(int workerNum,Semaphore semaphore){
this.workerNum = workerNum;
this.semaphore = semaphore;
}
@Override
public void run() {
try {
//工人获取机器
semaphore.acquire();
//打印工人获取到机器,开始工作
System.out.println(Thread.currentThread().getName()+" 开始工作");
//线程睡眠,模拟工作
Thread.sleep(1000);
//使用完毕,释放机器
semaphore.release();
System.out.println(Thread.currentThread().getName()+" 使用完毕,释放机器");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
int workers = 8;
Semaphore semaphore = new Semaphore(3);
for (int i=1;i<workers;i++){
new Thread(new Work(i,semaphore),String.valueOf(i)).start();
}
}
}
运行结果: