java并发的发布和订阅测试

现在编码的时候,为了处理消息,大家动不动就上个重器,例如MQ之类的。但很多时候,并不是那么有必要,因为数据量和并发其实远远不够。

可以替代的方案非常多,其中一个是java.util.concurrent

 

在jdk9及其以上,java.util.Observable已经被标注为过时,官方推荐使用java.beans或者是java.util.concurrent。

在发布订阅者模式中,有四个对象是需要关注的:

  1. 发布者
  2. 订阅者(消费者)
  3. 消息
  4. 并发

本文主要代码参考 https://www.cnblogs.com/zhangmingda/p/14715139.html

不过为了更加友好一些,对原有的代码做了适量的调整。

注:以下代码运行于windows11+JDK17

消息对象

package study.base.designPattern.observer.latest.flow;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class Message {
    private Integer qty;
    private Integer maxQty;
    private String content;
    private Map<String, Boolean> readStatus;

    public Map<String, Boolean> getReadStatus() {
        return readStatus;
    }

    public String getContent() {
        return content;
    }

    public boolean isFinished() {
        return qty.intValue() == maxQty.intValue();
    }

    public Message(String content, List<String> readerList) {
        this.content = content;
        this.maxQty = readerList.size();
        this.qty = 0;
        this.readStatus = new ConcurrentHashMap<>();
        for (String item : readerList) {
            readStatus.put(item, false);
        }
    }

    public void read(String readerName) {
        if (qty < maxQty) {
            if (readStatus.containsKey(readerName)) {
                Boolean isRead = readStatus.get(readerName);
                if (!isRead) {
                    synchronized (readStatus) {
                        readStatus.put(readerName, true);
                        qty++;
                        System.out.println("---|"+readerName + "正在进行" + this.content + "...." + qty);
                        if (qty==maxQty) {
                            System.out.println("\n---|所有人已经完成【"+this.content+"】\n");
                        }
                    }
                }
            }
        }
        

    }
}

 

消费者对象

package study.base.designPattern.observer.latest.flow;

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

public class Student implements Subscriber<Message> {

    private Subscription subscription;
    private String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public void onSubscribe(Subscription subscription) {
        System.out.println(name + "开始订阅[" + subscription.toString() + "]");
        subscription.request(1);
        this.subscription = subscription;
    }

    @Override
    public void onError(Throwable e) {
        System.out.println(e.getMessage());
    }

    @Override
    public void onComplete() {
        System.out.println(name + "关闭了订阅");
        Teacher.getLock().lock();
        Teacher.getCondition().signalAll();
        Teacher.getLock().unlock();

    }

    @Override
    public void onNext(Message message) {
        message.read(this.name);
        subscription.request(1);
        /**
         * 模拟延时--郊游的时候,时间长一些
         */
        try {
            if (message.getContent().equals("郊游")) {
                Thread.sleep(1300);
            }
            else {
                Thread.sleep(200);
            }
            
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

}

 

发布者和主程序

package study.base.designPattern.observer.latest.flow;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.SubmissionPublisher;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.serializer.SerializerFeature;

/**
 * https://www.cnblogs.com/zhangmingda/p/14715139.html 此类技术是观察者模式的一个并发实现
 * 
 * @author lzfto
 */
public class Teacher {
    private static Lock lock = new ReentrantLock(true);
    private static Condition condition = lock.newCondition();

    private volatile static CopyOnWriteArrayList<Message> subjectList = new CopyOnWriteArrayList<Message>();

    public static Lock getLock() {
        return lock;
    }

    public static Condition getCondition() {
        return condition;
    }

    public static void main(String[] args) throws InterruptedException {

        /**
         * 定义一个发布者,需要设定要发送消息的泛型数据类型
         */
        SubmissionPublisher<Message> teacher = new SubmissionPublisher<>();
        /**
         * 定义一个订阅者
         */
        List<String> studentList = Arrays.asList("mzd", "***", "luzhfiei", "海瑞");
        for (String readerName : studentList) {
            Student student = new Student(readerName);
            teacher.subscribe(student);
        }
        /**
         * 测试发布消息
         */

        subjectList.add(new Message("朗读", studentList));
        subjectList.add(new Message("劳动", studentList));
        subjectList.add(new Message("郊游", studentList));
        subjectList.add(new Message("射箭", studentList));

        subjectList.forEach(item -> {
            System.out.println("同学们!开始【" + item.getContent() + "】");
            teacher.submit(item);
        }); // 向订阅者发布数据,需要保持主线程存活,否则当前线程执行结束,发布者和订阅者都被销毁了。
        /**
         * 关闭消息发布
         */
        teacher.close(); // 关闭后,如果当前线程未退出,待订阅者所有消息都处理完毕才会运行订阅者的onComplete方法
        lock.lock();
        condition.await();
        lock.unlock();
        System.out.println(JSONArray.toJSONString(subjectList, SerializerFeature.PrettyFormat));
        ;
    }

}

测试后的输出(一种情况):

mzd开始订阅[java.util.concurrent.SubmissionPublisher$BufferedSubscription@12749d9e]
***开始订阅[java.util.concurrent.SubmissionPublisher$BufferedSubscription@1df086d4]
luzhfiei开始订阅[java.util.concurrent.SubmissionPublisher$BufferedSubscription@1e7629c2]
海瑞开始订阅[java.util.concurrent.SubmissionPublisher$BufferedSubscription@73e441ec]
同学们!开始【朗读】
同学们!开始【劳动】
同学们!开始【郊游】
同学们!开始【射箭】
---|mzd正在进行朗读....1
---|海瑞正在进行朗读....2
---|luzhfiei正在进行朗读....3
---|***正在进行朗读....4

---|所有人已经完成【朗读】

---|海瑞正在进行劳动....1
---|luzhfiei正在进行劳动....2
---|***正在进行劳动....3
---|mzd正在进行劳动....4

---|所有人已经完成【劳动】

---|***正在进行郊游....1
---|mzd正在进行郊游....2
---|luzhfiei正在进行郊游....3
---|海瑞正在进行郊游....4

---|所有人已经完成【郊游】

---|mzd正在进行射箭....1
---|***正在进行射箭....2
---|luzhfiei正在进行射箭....3
---|海瑞正在进行射箭....4

---|所有人已经完成【射箭】

luzhfiei关闭了订阅
***关闭了订阅
mzd关闭了订阅
海瑞关闭了订阅

subjectList的结果:

[
    {
        "content": "朗读",
        "finished": true,
        "readStatus": {
            "mzd": true,
            "海瑞": true,
            "***": true,
            "luzhfiei": true
        }
    },
    {
        "content": "劳动",
        "finished": true,
        "readStatus": {
            "mzd": true,
            "海瑞": true,
            "***": true,
            "luzhfiei": true
        }
    },
    {
        "content": "郊游",
        "finished": true,
        "readStatus": {
            "mzd": true,
            "海瑞": true,
            "***": true,
            "luzhfiei": true
        }
    },
    {
        "content": "射箭",
        "finished": true,
        "readStatus": {
            "mzd": true,
            "海瑞": true,
            "***": true,
            "luzhfiei": true
        }
    }
]

 

这只是一个非常简单的例子,距离生产还有很远的一个距离。

 

posted @ 2022-05-19 17:55  正在战斗中  阅读(146)  评论(0编辑  收藏  举报