Java多线程设计模式详解学习笔记七——Producer-Consumer

public class Main {
	public static void main(String[] args) {
		Table table=new Table(3);
		new MakerThread("MakerThread-1", table, 12345).start();
		new MakerThread("MakerThread-2", table, 54345).start();
		new MakerThread("MakerThread-3", table, 62345).start();
		new EaterThread("EaterThread-1", table, 23455).start();
		new EaterThread("EaterThread-2", table, 43455).start();
		new EaterThread("EaterThread-3", table, 53455).start();
	}
}
public class EaterThread extends Thread{
	private final Table table;
	private final Random random;
	
	public EaterThread(String name,Table table,long seed) {
		super(name);
		this.table=table;
		random=new Random(seed);
	}
	
	@Override
	public void run() {
		try {
			while (true) {
				String cake=table.take();
				Thread.sleep(random.nextInt(1000));
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
}
public class MakerThread extends Thread{
	private final Table table;
	private final Random random;
	private static int id=0;
	
	public MakerThread(String name,Table table,long seed) {
		super(name);
		this.table=table;
		random=new Random(seed);
	}

	@Override
	public void run() {
		try {
			while (true) {
				Thread.sleep(random.nextInt(1000));
				String cake="[ Cake No: "+nextId()+" by "+getName()+"]";
				table.put(cake);
			}
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
	
	private static synchronized int nextId() {
		return ++id;
	}
}
public class Table {
	private final String[] buffer;
	private int count;
	private int tail;
	private int head;
	
	public Table(int count) {
		buffer=new String[count];
		count=0;
		tail=0;
		head=0;
	}
	
	public synchronized String take() throws InterruptedException {
		while (count<=0) {
			wait();
		}
		String cake=buffer[head];
		head=(head+1)%buffer.length;
		count--;
		notifyAll();
		System.out.println(Thread.currentThread().getName()+" takes "+cake);
		return cake;
	}
	
	public synchronized void put(String cake) throws InterruptedException {
		System.out.println(Thread.currentThread().getName()+" put "+cake);
		while (count>=buffer.length) {
			wait();
		}
		buffer[tail]=cake;
		tail=(tail+1)%buffer.length;
		count++;
		notifyAll();
	}
}

运行就过如下:

MakerThread-1 put [ Cake No: 1 by MakerThread-1]
EaterThread-2 takes [ Cake No: 1 by MakerThread-1]
MakerThread-1 put [ Cake No: 2 by MakerThread-1]
EaterThread-1 takes [ Cake No: 2 by MakerThread-1]
MakerThread-1 put [ Cake No: 3 by MakerThread-1]
EaterThread-3 takes [ Cake No: 3 by MakerThread-1]
MakerThread-3 put [ Cake No: 4 by MakerThread-3]
EaterThread-2 takes [ Cake No: 4 by MakerThread-3]
MakerThread-2 put [ Cake No: 5 by MakerThread-2]
EaterThread-2 takes [ Cake No: 5 by MakerThread-2]
MakerThread-3 put [ Cake No: 6 by MakerThread-3]
EaterThread-1 takes [ Cake No: 6 by MakerThread-3]
MakerThread-1 put [ Cake No: 7 by MakerThread-1]
EaterThread-3 takes [ Cake No: 7 by MakerThread-1]
MakerThread-1 put [ Cake No: 8 by MakerThread-1]
MakerThread-1 put [ Cake No: 9 by MakerThread-1]
EaterThread-2 takes [ Cake No: 8 by MakerThread-1]
EaterThread-1 takes [ Cake No: 9 by MakerThread-1]
MakerThread-2 put [ Cake No: 10 by MakerThread-2]
MakerThread-2 put [ Cake No: 11 by MakerThread-2]

Producer-Consumer Pattern 的所有参与者

程序的类图如下



Producer是“生产者”的意思,是指产生数据的线程,而Consumer是“消费者”的意思,意指使用数据的线程。

生产者必须将数据安全的交给消费者。虽然这是这样的问题,但当生产者和消费者在不同线程上运行时,两者的处理速度差将是最大的问题。当消费者要取数据时生产者还没建立数据,或者是生产者建立出数据时消费者的状态还没办法接受数据等等。
Producer-Consumer Pattern是在生产者与消费者之间加入一个“桥梁参与者”,以这个桥梁参与者缓冲线程之间的处理速度差。Channel参与者介于Producer参与者、Consumer参与者之间,担任传递Data参与者中继站,通道的角色。

保护安全性的Channel参与者
范例程序中,Table类的put和take方法都是用了Guarded Suspension Pattern,但MakerThread类与EaterThread类都不想依于Table类的详细实现,也就是说MakerThread不比理会其他线程,只要调用put方法就好,而EaterThread也是只要会调用take方法就可以。使用synchronized、wait、notifyAll这些考略到多线程操作的程序代码,全部隐藏在Channel参与者Table类里面。

中间者存在的隐含的意义
因为Channel参与者的存在,Producer参与者和Consumer参与者这条多线程,才能保持协力、合作。而在在Single Thread Execution Pattern中曾经说过“Synchronized是在保护什么”?当时我们说过,思索线程的共享互斥问题时,把观察切入点放在“保护着什么”上面,会比较容易找到问题的结症。
上面的思维若整理成口诀,可以得到两句话:
一。线程的合作要想“放在中间的东西”
二。线程的互斥要想“应该保护的东西”

InterruptedException异常
Java的标准类链接库中,后面接着throws InterrupedException的方法的代表选手,有下面这3位:
Java.lang.Object类的wait方法
Java.lang.Thread类的sleep方法
Java.lang.Thread类的join方法
这个通常告诉我们下面两件事:
一、这是“需要花点时间”的方法
二、这是“可以取消”的方法
用一句话来说,后面接着throws InterruptedException的方法,是可能会花一点时间,但是可以取消的方法。
一、需要花点时间的方法
执行wait方法的线程,会进入等待区等待被notify/notifyAll,在等待期间,线程不会活动。故需要花费等待被notify/notifyAll的时间。
执行sleep方法的线程,会暂停执行参数内所设置的时间,这也是花费时间的方法。
执行join方法的线程,会等待到指定的线程结束为止。也就是会花费直到指定线程结束之前的这段时间
像上面三个方法,分别要等待“被notify/notifyAll、设置的时间、指定的线程结束”,的确都是“需要花点时间”的方法
二、可以取消的方法
因为需要画时间的操作,会降低程序的响应性,所以我们会希望像下面着阳光可以在中途放弃(取消)执行这个方法
   1、取消wait方法等待notify/notifyAll的操作
   2、取消sleep方法等待设置长度时间的限制
   3、取消join方法等待其他线程结束的操作

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Kafka 中,Producer 是用来发送消息到 Kafka 集群的组件。在本篇文章中,我们将介绍如何使用 Kafka 的 Java 客户端 API 来编写一个简单的 Producer。 1. 引入 Kafka 依赖 首先,需要在 Maven 或 Gradle 构建中引入 Kafka 客户端依赖: ```xml <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>2.8.0</version> </dependency> ``` 2. 创建 Producer 实例 接下来,在 Java 代码中创建一个 KafkaProducer 实例: ```java Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); Producer<String, String> producer = new KafkaProducer<>(props); ``` 其中,bootstrap.servers 是必须设置的属性,用于指定 Kafka 集群中至少一个 Broker 的地址。key.serializer 和 value.serializer 用于指定消息的键和值的序列化器。这里我们使用的是 StringSerializer,也可以使用其他序列化器实现自定义序列化逻辑。 3. 发送消息 一旦创建了 KafkaProducer 实例,就可以使用它来发送消息到指定的 Kafka 主题: ```java ProducerRecord<String, String> record = new ProducerRecord<>("test-topic", "key", "value"); producer.send(record); ``` 这里的 ProducerRecord 构造函数中,第一个参数是要发送消息的主题名称,第二个参数是消息的键,第三个参数是消息的值。send() 方法用于将 ProducerRecord 发送到 Kafka 集群。 4. 关闭 Producer 在使用完 Producer 后,需要关闭它以释放资源: ```java producer.close(); ``` 完整代码示例: ```java import org.apache.kafka.clients.producer.*; import java.util.Properties; public class KafkaProducerExample { public static void main(String[] args) { Properties props = new Properties(); props.put("bootstrap.servers", "localhost:9092"); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); Producer<String, String> producer = new KafkaProducer<>(props); ProducerRecord<String, String> record = new ProducerRecord<>("test-topic", "key", "value"); producer.send(record); producer.close(); } } ``` 这就是一个简单的 Kafka Producer 的使用示例。在实际应用中,还可以根据需要设置其他属性,例如消息的分区策略、消息的压缩方式等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值