併發程式設計:自定義併發類:自定義非同步流(釋出與訂閱)

博風發表於2020-10-17

目錄

主要內容(參考程式設計流)

一、主程式

二、釋出者(Publisher)

三、釋出任務類(PublisherTask)

四、訂閱實體(ConsumerData)

五、訂閱者(消費者Consumer extends Subscriber)

六、訂閱資訊(Subscription)

七、元素資訊(News)

八、執行結果


主要內容(參考程式設計流

  • Flow.Publisher:釋出者(提供一個方法來接收Subscriber,進行訊息釋出)
  • Flow.Subscriber:訂閱者(提供4個方法,分別用於:訂閱完畢時,出現異常時,新元素被請求時,釋出者註冊訂閱者時。)
  • Flow.Subscription:訂閱(提供釋出者與消費者之間的訂閱處理)

一、主程式

  1. 實現一個釋出者(Publisher),兩個消費者(Consumer extends Subscriber),讓它們建立訂閱關係。
  2. 建立元素(News),由釋出者進行釋出操作(釋出操作會建立獨立的釋出任務,由執行器執行。)
package xyz.jangle.thread.test.n8_xiii.asyncstream;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 8.13、自定義非同步流(釋出與訂閱)
 * 
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年10月16日 下午3:19:33
 * 
 */
public class M {

	public static void main(String[] args) {
		var publisher = new MyPublisher();
		var consumer1 = new Consumer("Consumer 1");
		var consumer2 = new Consumer("Consumer 2");
		publisher.subscribe(consumer1);
		publisher.subscribe(consumer2);
		System.out.println("M:start");
		var news = new News();
		news.setTitle("My first news");
		news.setContent("This is the content");
		news.setDate(new Date());
		publisher.publish(news);
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		news = new News();
		news.setTitle("My second news");
		news.setContent("This is the content for second news");
		news.setDate(new Date());
		publisher.publish(news);
		System.out.println("M:end");
	}

}

二、釋出者(Publisher)

釋出者包含訂閱者(Subscriber)訂閱資訊(Subscription)結合的實體(ConsumerData訂閱實體)物件列表。

釋出者包含執行器(ThreadPoolExecutor),釋出者釋出資訊時,會將元素資訊(News)訂閱實體構造成釋出任務(PublisherTask),由執行器執行。

package xyz.jangle.thread.test.n8_xiii.asyncstream;

import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.Flow.Publisher;
import java.util.concurrent.Flow.Subscriber;

/**
 * 
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年10月16日 下午4:16:54
 * 
 */
public class MyPublisher implements Publisher<News> {

	private ConcurrentLinkedDeque<ConsumerData> consumers;
	private ThreadPoolExecutor executor;

	public MyPublisher() {
		consumers = new ConcurrentLinkedDeque<ConsumerData>();
		executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
	}

	@Override
	public void subscribe(Subscriber<? super News> subscriber) {
		ConsumerData consumerData = new ConsumerData();
		consumerData.setConsumer((Consumer) subscriber);
		var subscription = new MySubscription();
		consumerData.setSubscription(subscription);
		subscriber.onSubscribe(subscription);
		consumers.add(consumerData);
	}
	
	/**
	 *   釋出元素(為每個訂閱者建立一個執行緒並提交給執行器執行。
	 * @param news
	 */
	public void publish(News news) {
		consumers.forEach(consumerData -> {
			try {
				executor.execute(new PublisherTask(consumerData, news));
			} catch (Exception e) {
				consumerData.getConsumer().onError(e);
			}
		});
	}

}

三、釋出任務類(PublisherTask)

package xyz.jangle.thread.test.n8_xiii.asyncstream;

/**
 *  釋出任務類
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年10月16日 下午4:07:54
 * 
 */
public class PublisherTask implements Runnable {

	private ConsumerData consumerData;
	private News news;

	public PublisherTask(ConsumerData consumerData, News news) {
		super();
		this.consumerData = consumerData;
		this.news = news;
	}

	@Override
	public void run() {
		MySubscription subscription = consumerData.getSubscription();
		if (!subscription.isCanceled() && subscription.getRequested() > 0) {
			consumerData.getConsumer().onNext(news);
			subscription.decreaseRequested();
		}
	}

}

四、訂閱實體(ConsumerData)

package xyz.jangle.thread.test.n8_xiii.asyncstream;

/**
 *  訂閱者資訊實體
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年10月16日 下午4:03:35
 * 
 */
public class ConsumerData {

	private Consumer consumer;
	private MySubscription subscription;

	public Consumer getConsumer() {
		return consumer;
	}

	public void setConsumer(Consumer consumer) {
		this.consumer = consumer;
	}

	public MySubscription getSubscription() {
		return subscription;
	}

	public void setSubscription(MySubscription subscription) {
		this.subscription = subscription;
	}

}

五、訂閱者(消費者Consumer extends Subscriber)

package xyz.jangle.thread.test.n8_xiii.asyncstream;

import java.util.concurrent.Flow.Subscriber;
import java.util.concurrent.Flow.Subscription;

/**
 * 訂閱者(消費者)
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年10月16日 下午3:25:14
 * 
 */
public class Consumer implements Subscriber<News> {

	private Subscription subscription;

	private String name;

	public Consumer(String name) {
		super();
		this.name = name;
	}

	@Override
	public void onSubscribe(Subscription subscription) {
		this.subscription = subscription;
		subscription.request(1);
		System.out.println(Thread.currentThread().getName() + ":onSubscribe() ******");
	}

	@Override
	public void onNext(News item) {
		System.out.println(Thread.currentThread().getName() + ":" + name + ":onNext() ******" + item);
		subscription.request(1);

	}

	@Override
	public void onError(Throwable throwable) {
		System.out.println(Thread.currentThread().getName() + ":onError() ******");
	}

	@Override
	public void onComplete() {
		System.out.println(Thread.currentThread().getName() + ":onComplete() ******");
	}

}

六、訂閱資訊(Subscription)

package xyz.jangle.thread.test.n8_xiii.asyncstream;

import java.util.concurrent.Flow.Subscription;

/**
 *  訂閱
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年10月16日 下午3:37:50
 * 
 */
public class MySubscription implements Subscription {

	private boolean canceled = false;

	private long requested = 0;

	@Override
	public void request(long n) {
		requested += n;
	}

	@Override
	public void cancel() {
		canceled = true;
	}

	public boolean isCanceled() {
		return canceled;
	}

	public long getRequested() {
		return requested;
	}

	public void decreaseRequested() {
		requested--;
	}

}

七、元素資訊(News)

package xyz.jangle.thread.test.n8_xiii.asyncstream;

import java.util.Date;

/**
 * 元素類
 * 
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年10月16日 下午3:23:03
 * 
 */
public class News {

	private String title, content;

	private Date date;

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}

	@Override
	public String toString() {
		return "News [title=" + title + ", content=" + content + ", date=" + date + "]";
	}

}

八、執行結果

main:onSubscribe() ******
main:onSubscribe() ******
M:start
pool-1-thread-1:Consumer 1:onNext() ******News [title=My first news, content=This is the content, date=Fri Oct 16 16:52:44 CST 2020]
pool-1-thread-2:Consumer 2:onNext() ******News [title=My first news, content=This is the content, date=Fri Oct 16 16:52:44 CST 2020]
M:end
pool-1-thread-3:Consumer 1:onNext() ******News [title=My second news, content=This is the content for second news, date=Fri Oct 16 16:52:45 CST 2020]
pool-1-thread-4:Consumer 2:onNext() ******News [title=My second news, content=This is the content for second news, date=Fri Oct 16 16:52:45 CST 2020]

 

相關文章