2022年06月28日我们讲到了 传统的线程通讯
目录
1.使用Condition实现线程通讯
如果我们使用的是 lock对象保证的线程同步,
则我们需要用 condition对象实现线程通讯
使用condition对象调用 await() signal() signalAll() 三个方法就可以
效果完全一样
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class BankAccount {
// 上次我们的银行账户类就变成了这样
private boolean flag = false; // flag 为 false表示账户里没钱
// 创建一个 lock对象
private ReentrantLock lock = new ReentrantLock();
// 使用 lock对象创建一个 Condition对象
private Condition condition = lock.newCondition();
// 取钱方法
public void drawMoney() throws Exception {
lock.lock();
if (this.flag) {
System.out.println("取走了800元,当前账户余额为0!");
this.flag = false;
Thread.sleep(1000);
condition.signalAll(); // 唤醒存款线程
} else {
// 如果账户里没钱 则取款线程进入等待状态
condition.await();
}
lock.unlock();
}
// 存钱方法
public void depositMoney() throws Exception {
lock.lock();
if (flag) {
// 如果账户里有钱 则存款线程进入等待状态
condition.await();
} else {
System.out.println("存入了800元,当前账户余额为800元");
this.flag = true;
Thread.sleep(1000);
condition.signalAll(); // 唤醒取款线程
}
lock.unlock();
}
}
现在我们来写一个题目:
我们有 甲 乙 丙 三个线程,向文件中写入数据, 一个线程写四行
要求写一行 换一个线程 写一行 换一个线程 直到全部写完
import java.io.FileOutputStream;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Output {
// 这是我们的 写输出流类
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// operator 表示的是当前应该由 哪个线程操作
private String operator = "甲";
// 这个 OutputStream()方法 用来向文件中写数据
public void OutputStream(List<String> list) throws Exception {
lock.lock();
String name = Thread.currentThread().getName();
// 如果应该由当前线程操作
if (name.equals(operator)){
// 则从传入的 List集合中取出第一个数据 取一个 删除一个
String line=list.remove(0);
// 这里创建一个输出流 指定往哪个文件里写
FileOutputStream output = new FileOutputStream("./file/test1.txt", true);
// 写入一行数据
output.write(line.getBytes());
//写入一行变更一下要求的线程名称
switch (operator) {
case "甲":
operator = "乙";
break;
case "乙":
operator = "丙";
break;
case "丙":
operator = "甲";
break;
}
// 唤醒其他所有线程
condition.signalAll();
output.close();
}else {
// 如果不该当前线程操作 则它需要等待
condition.await();
}
lock.unlock();
}
}
import java.util.List;
public class OutputThread extends Thread {
// 这是我们的写入线程类
private Output output;
private List<String> list;
// 构造方法中要传入 output对象 线程名称 要输入的内容
public OutputThread(Output output,String name,List<String> list) {
super(name);
this.output = output;
this.list=list;
}
@Override
public void run() {
try {
// 当集合里的数据还没有取完时 调用 OutputStream()方法 写入数据
while (list.size()>0){
output.OutputStream(list);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
import java.util.ArrayList;
import java.util.List;
public class OutputTest {
public static void main(String[] args) {
// 这个是我们的测试类
List<String> list1=new ArrayList<>();
List<String> list2=new ArrayList<>();
List<String> list3=new ArrayList<>();
list1.add("甲甲甲甲甲甲甲甲甲甲甲甲甲\n");
list1.add("甲甲甲甲甲甲甲甲甲甲甲甲甲\n");
list1.add("甲甲甲甲甲甲甲甲甲甲甲甲甲\n");
list1.add("甲甲甲甲甲甲甲甲甲甲甲甲甲\n");
list2.add("乙乙乙乙乙乙乙乙乙乙乙乙乙\n");
list2.add("乙乙乙乙乙乙乙乙乙乙乙乙乙\n");
list2.add("乙乙乙乙乙乙乙乙乙乙乙乙乙\n");
list2.add("乙乙乙乙乙乙乙乙乙乙乙乙乙\n");
list3.add("丙丙丙丙丙丙丙丙丙丙丙丙丙\n");
list3.add("丙丙丙丙丙丙丙丙丙丙丙丙丙\n");
list3.add("丙丙丙丙丙丙丙丙丙丙丙丙丙\n");
list3.add("丙丙丙丙丙丙丙丙丙丙丙丙丙\n");
Output output=new Output();
new OutputThread(output,"甲",list1).start();
new OutputThread(output,"乙",list2).start();
new OutputThread(output,"丙",list3).start();
}
}
输出结果:
2.使用阻塞队列进行线程通讯
// 创建一个 BlockingQueue对象 这个3是指定的容量
ArrayBlockingQueue<String> queue=new ArrayBlockingQueue<>(3);
queue.put(); // 向队列中放入元素
queue.take(); // 从队列中取出元素
public class Producer extends Thread{
// 这是我们的生产者线程
// 在线程类里需要定义一个阻塞队列
private ArrayBlockingQueue<String> queue=null;
Random random=new Random();
public Producer(ArrayBlockingQueue queue){
this.queue=queue;
}
private List<String> list=new ArrayList<>();
@Override
public void run() {
for (int i = 0; i <=10; i++) {
// 我们生产者向队列中放入10个产品
// 每放1个产品休眠一段时间
try {
random.setSeed(100);
String value="产品"+i;
this.queue.put(value);
System.out.println("生产者放入产品"+value);
Thread.sleep(random.nextInt(2000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Customer extends Thread{
// 这是我们的消费者类
// 这样创建一个BlockingQueue对象
private ArrayBlockingQueue<String> queue=null;
Random random=new Random();
public Customer(ArrayBlockingQueue queue){
this.queue=queue;
}
@Override
public void run() {
for (int i = 0; i <= 10; i++) {
try {
// 消费者也是每取一个产品休息一段时间
random.setSeed(100);
String value=this.queue.take();
System.out.println("消费者取走产品"+value);
Thread.sleep(random.nextInt(4000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Test {
public static void main(String[] args) {
// 这是我们的测试类
ArrayBlockingQueue<String> queue=new ArrayBlockingQueue<>(3);
new Producer(queue).start();
new Customer(queue).start();
}
}
这就是使用阻塞队列实现线程通讯
我们再写一个题目
我们有一个厨师 随机从红烧肉 西兰花 糖醋里脊 做一份放入队列中
一次最多放一份食物
消费者线程有三个 胖子 美女 小兽
胖子只拿红烧肉 美女只拿西兰花 小兽只拿糖醋里脊
厨师放入 10 次食物,其他三个消费者线程取走各自的食物,
三个消费者成功取走的次数加起来为 10 次,程序结束。
public class Chief extends Thread{ // 这是我们的厨师线程 private ArrayBlockingQueue<String> queue=null; private Random random=new Random(); public Chief(ArrayBlockingQueue<String> queue) { this.queue = queue; } @Override public void run() { try { for (int i = 0; i <10; i++) { // 随机产生一个3以内的数字 决定做哪份食物 if (random.nextInt(3)==0){ queue.put("红烧肉"); System.out.println("厨师放入了红烧肉"); }else if (random.nextInt(3)==1){ queue.put("西兰花"); System.out.println("厨师放入了西兰花"); }else if (random.nextInt(3)==2){ queue.put("糖醋里脊"); System.out.println("厨师放入了糖醋里脊"); } Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } }
public class Customer extends Thread{ // 这是我们的消费者线程 private ArrayBlockingQueue<String> queue=null; public Customer(ArrayBlockingQueue<String> queue) { this.queue = queue; } @Override public void run() { try { for (int i = 0; i <10; i++) { if (queue.peek()!=null){ // 判断这应该是谁的食物 switch (queue.peek()) { case "红烧肉": System.out.println("胖子取走了红烧肉"); queue.take(); break; case "西兰花": System.out.println("美女取走了西兰花"); queue.take(); break; case "糖醋里脊": System.out.println("小兽取走了糖醋里脊"); queue.take(); break; } } Thread.sleep(1500); } } catch (Exception e) { e.printStackTrace(); } } }
public class Test { public static void main(String[] args) { // 这是我们的测试类 ArrayBlockingQueue<String> food = new ArrayBlockingQueue<String>(1); new Chief(food).start(); new Customer(food).start(); } }
THE END(^_−)☆