Subject详解
- 一、概述
- 二、AsyncSubject(只发射最后一个值)
- 三、PublishSubject(实时发布)
- 四、BehaviorSubject(保留最新值)
- 五、ReplaySubject(重放所有数据)
- 六、UnicastSubject(单播Subject支持背压)
- 七、Subject高级用法
- 八、Subject内存管理
- 九、Subject性能优化
- 十、常见问题解决方案
- 十一、最佳实践
一、概述
1.1、核心概念
Subject是RxJava中的特殊类型,它既是Observer(可以订阅其他Observable),又是Observable(可以被其他Observer订阅)。它作为事件总线或中继器使用。
继承关系:
java
// Subject 继承关系
public abstract class Subject<T> extends Observable<T> implements Observer<T> {
// 核心方法
public abstract boolean hasObservers();
public final boolean hasComplete();
public final boolean hasThrowable();
public final Throwable getThrowable();
public final boolean hasComplete();
}
// 支持背压的Flowable版本
public abstract class FlowableProcessor<T> extends Flowable<T> implements FlowableSubscriber<T>, Processor<T, T> {
public abstract boolean hasSubscribers();
}
1.2、Subject类型
| 类型 | 特性 |
|---|---|
PublishSubject |
实时发布 |
BehaviorSubject |
保留最新值 |
ReplaySubject |
重放所有数据 |
AsyncSubject |
只发射最后一个值 |
UnicastSubject |
单播Subject |
FlowableProcessor |
支持背压的Flowable版本 |
二、AsyncSubject(只发射最后一个值)
2.1、核心特性
- Observer会接收AsyncSubject的onComplete(之前的最后一个数据
- 如果源Observable没有发射任何值就完成,AsyncSubject也不会发射任何值
- 如果源Observable发生错误,AsyncSubject会传递这个错误
java
@Test
public void testAsyncSubject() {
//基本用法
AsyncSubject<String> subject = AsyncSubject.create();
//订阅者1
subject.subscribe(
data -> System.out.println("Subscriber 1:" + data),
error -> System.out.println("Error:" + error),
() -> System.out.println("Completed")
);
subject.onNext("Ignore 1");
subject.onNext("Ignore 2");
subject.onNext("Last Value");//只有这个值会被发射
subject.onComplete();
//订阅者2(也能收到最后的值)
subject.subscribe(data -> System.out.println("Subscriber 2:" + data));
}
Subscriber 1:Last Value
Completed
Subscriber 2:Last Value
2.2、使用场景
java
// 1. 异步计算结果
public class AsyncCalculator {
private final AsyncSubject<Double> resultSubject = AsyncSubject.create();
public void calculateAsync(List<Double> numbers) {
Completable.fromAction(() -> {
double sum = 0;
for (Double num : numbers) {
sum += num;
// 中间结果被忽略
resultSubject.onNext(sum);
}
resultSubject.onComplete();
}).subscribeOn(Schedulers.computation()).subscribe();
}
public Observable<Double> getResult() {
return resultSubject;
}
}
// 2. 网络请求最终结果
public class ApiClient {
private final AsyncSubject<Response> responseSubject = AsyncSubject.create();
public void executeRequest(Request request) {
apiService.call(request)
.subscribe(
response -> {
responseSubject.onNext(response);
responseSubject.onComplete();
},
error -> responseSubject.onError(error)
);
}
public Observable<Response> getResponse() {
return responseSubject;
}
}
// 3. 数据库操作结果
public class DatabaseOperation<T> {
private final AsyncSubject<T> operationSubject = AsyncSubject.create();
public void executeOperation(Operation<T> operation) {
database.execute(operation)
.subscribe(
result -> {
operationSubject.onNext(result);
operationSubject.onComplete();
},
error -> operationSubject.onError(error)
);
}
public Observable<T> getResult() {
return operationSubject;
}
}
三、PublishSubject(实时发布)
3.1、核心特性
- 只向订阅时已发射的数据之后的订阅者发射数据
- 不缓存任何数据
- 订阅者只能收到订阅之后发射的数据
java
@Test
public void testPublishSubject() {
//基本用法
PublishSubject<String> subject = PublishSubject.create();
//订阅者1
subject.subscribe(
data -> System.out.println("Subscriber 1:" + data),
error -> System.out.println("Subscriber 1 Error:" + error),
() -> System.out.println("Subscriber 1 Completed")
);
//发射数据
subject.onNext("Data 1");
subject.onNext("Data 2");
//订阅者2(收不到之前的数据)
subject.subscribe(
data -> System.out.println("Subscriber 2:" + data),
error -> System.out.println("Subscriber 2 Error:" + error),
() -> System.out.println("Subscriber 2 Completed")
);
subject.onNext("Data 3");
subject.onComplete();
}
Subscriber 1:Data 1
Subscriber 1:Data 2
Subscriber 1:Data 3
Subscriber 2:Data 3
Subscriber 1 Completed
Subscriber 2 Completed
3.2、使用场景
java
// 1. 事件总线
public class EventBus {
private static final PublishSubject<Event> bus = PublishSubject.create();
public static void post(Event event) {
bus.onNext(event);
}
public static Observable<Event> observe() {
return bus;
}
}
// 2. 实时数据更新
public class RealTimeDataManager {
private final PublishSubject<StockPrice> priceSubject = PublishSubject.create();
public void updatePrice(String symbol, double price) {
priceSubject.onNext(new StockPrice(symbol, price));
}
public Observable<StockPrice> getPriceStream() {
return priceSubject.filter(price -> price != null);
}
}
// 3. 用户交互事件
public class UserInteractionHandler {
private final PublishSubject<ClickEvent> clickSubject = PublishSubject.create();
public void onButtonClicked(View view) {
clickSubject.onNext(new ClickEvent(view.getId(), System.currentTimeMillis()));
}
public Observable<ClickEvent> getClicks() {
return clickSubject.debounce(300, TimeUnit.MILLISECONDS);
}
}
四、BehaviorSubject(保留最新值)
4.1、核心特性
- 向订阅者发射最近的一个值和之后的所有值
- 需要初始值(默认值)
- 新订阅者立即收到最近的值
java
@Test
public void testBehaviorSubject() {
//基本用法
BehaviorSubject<String> subject = BehaviorSubject.createDefault("Initial");
//订阅者1
subject.subscribe(data -> System.out.println("Subscriber 1:" + data));
subject.onNext("Update 1");
subject.onNext("Update 2");
//订阅者2(立即收到最近的值update 2)
subject.subscribe(data -> System.out.println("Subscriber 2:" + data));
subject.onNext("Update 3");
subject.onComplete();
}
Subscriber 1:Initial
Subscriber 1:Update 1
Subscriber 1:Update 2
Subscriber 2:Update 2
Subscriber 1:Update 3
Subscriber 2:Update 3
4.2、使用场景
java
// 1. 状态管理
public class AppStateManager {
private final BehaviorSubject<AppState> stateSubject =
BehaviorSubject.createDefault(AppState.IDLE);
public void setState(AppState newState) {
stateSubject.onNext(newState);
}
public Observable<AppState> getStateObservable() {
return stateSubject.distinctUntilChanged();
}
public AppState getCurrentState() {
return stateSubject.getValue(); // 获取当前值
}
}
// 2. 数据缓存
public class CacheManager<T> {
private final BehaviorSubject<Optional<T>> cacheSubject =
BehaviorSubject.createDefault(Optional.empty());
public void updateCache(T data) {
cacheSubject.onNext(Optional.of(data));
}
public void clearCache() {
cacheSubject.onNext(Optional.empty());
}
public Observable<Optional<T>> getCacheStream() {
return cacheSubject;
}
public Optional<T> getCurrentCache() {
return cacheSubject.getValue();
}
}
// 3. 表单验证
public class FormValidator {
private final BehaviorSubject<Boolean> validSubject =
BehaviorSubject.createDefault(false);
public void validate(String input) {
boolean isValid = input != null && !input.trim().isEmpty();
validSubject.onNext(isValid);
}
public Observable<Boolean> getValidationStream() {
return validSubject;
}
public boolean isValid() {
return Boolean.TRUE.equals(validSubject.getValue());
}
}
五、ReplaySubject(重放所有数据)
5.1、核心特性
- 向所有订阅者发射所有已发射的数据
- 可配置缓冲区大小和时间窗口
- 新订阅者立即收到所有历史数据
java
@Test
public void testReplaySubject() throws InterruptedException {
//1. 无限缓存
ReplaySubject<String> unlimited = ReplaySubject.create();
unlimited.onNext("Data 1");
unlimited.onNext("Data 2");
unlimited.subscribe(data -> System.out.println("Subscriber:" + data));
//输出:Data 1, Data 2
//2.限制缓存大小
ReplaySubject<Integer> sizeLimited = ReplaySubject.createWithSize(2);
sizeLimited.onNext(1);
sizeLimited.onNext(2);
sizeLimited.onNext(3);//超出限制,1被丢弃
sizeLimited.subscribe(System.out::println);
//输出:2,3
//限制时间窗口
ReplaySubject<String> timeLimited = ReplaySubject.createWithTime(1, TimeUnit.SECONDS, Schedulers.computation());
timeLimited.onNext("Data 1");
Thread.sleep(500);
timeLimited.onNext("Data 2");
Thread.sleep(600);//Data1过期
timeLimited.subscribe(System.out::println);
//输出:Data 2
//4. 限制大小和时间
ReplaySubject<String> bounded = ReplaySubject.createWithTimeAndSize(
1, TimeUnit.SECONDS,//时间窗口
Schedulers.computation(),
100
);
Thread.sleep(6000L);
}
Subscriber:Data 1
Subscriber:Data 2
2
3
Data 2
5.2、使用场景
java
// 1. 日志记录器
public class Logger {
private final ReplaySubject<LogEntry> logSubject =
ReplaySubject.createWithSize(1000); // 保留最近1000条日志
public void log(Level level, String message) {
logSubject.onNext(new LogEntry(level, message, System.currentTimeMillis()));
}
public Observable<LogEntry> getLogStream() {
return logSubject;
}
public List<LogEntry> getRecentLogs(int count) {
List<LogEntry> logs = new ArrayList<>();
logSubject.takeLast(count).subscribe(logs::add);
return logs;
}
}
// 2. 聊天消息历史
public class ChatRoom {
private final ReplaySubject<Message> messageSubject =
ReplaySubject.createWithTime(1, TimeUnit.HOURS, Schedulers.io());
public void sendMessage(User sender, String content) {
messageSubject.onNext(new Message(sender, content, System.currentTimeMillis()));
}
public Observable<Message> getMessageStream() {
return messageSubject;
}
public void replayHistoryFor(User user) {
// 新用户加入时重放历史消息
messageSubject
.takeUntil(msg -> msg.getTimestamp() > System.currentTimeMillis() - 300000) // 最近5分钟
.subscribe(msg -> sendToUser(user, msg));
}
}
// 3. 传感器数据记录
public class SensorDataRecorder {
private final ReplaySubject<SensorData> dataSubject =
ReplaySubject.createWithTimeAndSize(
10, TimeUnit.MINUTES, // 10分钟窗口
10000, // 最多10000个数据点
Schedulers.computation()
);
public void recordData(SensorData data) {
dataSubject.onNext(data);
}
public Observable<SensorData> getDataStream() {
return dataSubject;
}
public Observable<SensorData> getRecentData(long duration, TimeUnit unit) {
long cutoff = System.currentTimeMillis() - unit.toMillis(duration);
return dataSubject.filter(data -> data.getTimestamp() >= cutoff);
}
}
六、UnicastSubject(单播Subject支持背压)
6.1、核心特性
- 只允许一个订阅者
- 支持背压
- 如果没有订阅者,会缓存数据直到有订阅者订阅
java
@Test
public void testUnicastSubject() {
//基本用法
UnicastSubject<String> subject = UnicastSubject.create();
//发射数据(还咩有订阅者,数据被缓存)
subject.onNext("Cached 1");
subject.onNext("Cached 2");
//订阅者(立即受到缓存的数据)
subject.subscribe(
data -> System.out.println("Received:" + data),
error -> System.out.println("Error:" + error),
() -> System.out.println("Completed")
);
subject.onNext("Live 1");
subject.onComplete();
//尝试第二个订阅者会抛异常
try {
subject.subscribe(data -> System.out.println("Second:" + data));
} catch (IllegalStateException e) {
System.out.println("只能有一个订阅者:" + e.getMessage());
}
}
Received:Cached 1
Received:Cached 2
Received:Live 1
Completed
6.2、使用场景
java
// 1. 单消费者队列
public class SingleConsumerQueue<T> {
private final UnicastSubject<T> queueSubject = UnicastSubject.create();
public void enqueue(T item) {
queueSubject.onNext(item);
}
public void complete() {
queueSubject.onComplete();
}
public Observable<T> getConsumerStream() {
return queueSubject
.onBackpressureBuffer() // 支持背压
.observeOn(Schedulers.io());
}
}
// 2. 任务处理器
public class TaskProcessor {
private final UnicastSubject<Task> taskSubject = UnicastSubject.create();
private Disposable processorDisposable;
public TaskProcessor() {
// 启动处理线程
processorDisposable = taskSubject
.observeOn(Schedulers.io())
.subscribe(this::processTask);
}
public void submitTask(Task task) {
taskSubject.onNext(task);
}
public void shutdown() {
taskSubject.onComplete();
if (processorDisposable != null && !processorDisposable.isDisposed()) {
processorDisposable.dispose();
}
}
private void processTask(Task task) {
// 处理任务
}
}
// 3. 数据序列化写入
public class SerialWriter {
private final UnicastSubject<byte[]> writeSubject = UnicastSubject.create();
private final OutputStream outputStream;
public SerialWriter(OutputStream outputStream) {
this.outputStream = outputStream;
// 单个写入线程
writeSubject
.observeOn(Schedulers.io())
.subscribe(
data -> outputStream.write(data),
error -> System.err.println("Write error: " + error),
() -> {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
);
}
public void write(byte[] data) {
writeSubject.onNext(data);
}
public void close() {
writeSubject.onComplete();
}
}
七、Subject高级用法
7.1、Subject的序列化
java
// Subject默认不是线程安全的
public class SerializedSubjectExample {
// 1. 使用toSerialized()方法
public static PublishSubject<String> createSerializedSubject() {
PublishSubject<String> subject = PublishSubject.create();
return subject.toSerialized(); // 转换为线程安全的Subject
}
// 2. 直接创建序列化Subject
public static BehaviorSubject<String> createSerializedBehaviorSubject() {
return BehaviorSubject.<String>create().toSerialized();
}
// 使用示例
public static void concurrentAccessExample() {
PublishSubject<String> subject = PublishSubject.create().toSerialized();
// 多线程并发访问
ExecutorService executor = Executors.newFixedThreadPool(5);
// 多个线程同时发射数据
for (int i = 0; i < 10; i++) {
final int index = i;
executor.submit(() -> {
subject.onNext("Data from thread " + Thread.currentThread().getId() + "-" + index);
});
}
// 订阅
subject.subscribe(data ->
System.out.println("Received: " + data + " on thread " + Thread.currentThread().getId())
);
executor.shutdown();
}
}
// 序列化Subject的原理
public class CustomSerializedSubject<T> extends Subject<T> {
private final Subject<T> actual;
private volatile boolean emitting;
private final List<T> queue = new ArrayList<>();
public CustomSerializedSubject(Subject<T> actual) {
this.actual = actual;
}
@Override
public void onNext(T t) {
synchronized (this) {
if (emitting) {
queue.add(t);
return;
}
emitting = true;
}
actual.onNext(t);
// 清空队列
drainLoop();
}
private void drainLoop() {
List<T> localQueue;
synchronized (this) {
localQueue = new ArrayList<>(queue);
queue.clear();
if (localQueue.isEmpty()) {
emitting = false;
return;
}
}
for (T item : localQueue) {
actual.onNext(item);
}
drainLoop();
}
// 其他方法实现...
}
7.2、Subject组合模式
java
public class SubjectComposition {
// 1. 多层Subject
public static class MultiLayerEventBus {
private final PublishSubject<SystemEvent> systemBus = PublishSubject.create();
private final PublishSubject<UserEvent> userBus = PublishSubject.create();
private final PublishSubject<NetworkEvent> networkBus = PublishSubject.create();
// 合并所有事件
private final Observable<Event> allEvents = Observable.merge(
systemBus.map(e -> (Event)e),
userBus.map(e -> (Event)e),
networkBus.map(e -> (Event)e)
);
public void postSystemEvent(SystemEvent event) {
systemBus.onNext(event);
}
public void postUserEvent(UserEvent event) {
userBus.onNext(event);
}
public Observable<Event> getAllEvents() {
return allEvents;
}
public Observable<SystemEvent> getSystemEvents() {
return systemBus;
}
}
// 2. Subject链
public static class ProcessingPipeline {
private final PublishSubject<RawData> input = PublishSubject.create();
private final BehaviorSubject<ProcessedData> output = BehaviorSubject.create();
public ProcessingPipeline() {
// 构建处理链
input
.observeOn(Schedulers.computation())
.map(this::validate)
.filter(Objects::nonNull)
.map(this::transform)
.map(this::enrich)
.subscribe(
output::onNext,
output::onError
);
}
public void feedData(RawData data) {
input.onNext(data);
}
public Observable<ProcessedData> getOutput() {
return output;
}
private RawData validate(RawData data) {
return data.isValid() ? data : null;
}
private ProcessedData transform(RawData data) {
return new ProcessedData(data);
}
private ProcessedData enrich(ProcessedData data) {
return data.enrich();
}
}
// 3. Subject作为桥接
public static class AdapterBridge {
private final PublishSubject<LegacyEvent> legacyInput = PublishSubject.create();
private final PublishSubject<ModernEvent> modernOutput = PublishSubject.create();
public AdapterBridge() {
// 将旧系统事件转换为新系统事件
legacyInput
.map(this::adaptEvent)
.subscribe(modernOutput::onNext);
}
public void receiveLegacyEvent(LegacyEvent event) {
legacyInput.onNext(event);
}
public Observable<ModernEvent> getModernEvents() {
return modernOutput;
}
private ModernEvent adaptEvent(LegacyEvent legacy) {
return new ModernEvent(
legacy.getId(),
legacy.getTimestamp(),
legacy.getPayload()
);
}
}
}
7.3、Subject的背压处理
java
public class BackpressureWithSubject {
// 1. 使用FlowableProcessor(支持背压的Subject)
public static class BackpressureEventBus {
private final PublishProcessor<Event> processor = PublishProcessor.create();
public void postEvent(Event event) {
processor.onNext(event);
}
public Flowable<Event> getEventStream() {
return processor
.onBackpressureBuffer(1000) // 缓冲区大小
.onBackpressureDrop(dropped ->
System.out.println("Dropped event: " + dropped)
);
}
}
// 2. 使用SerializedSubject处理背压
public static class SerializedBackpressureSubject<T> {
private final PublishSubject<T> subject = PublishSubject.create();
private final SerializedSubject<T> serialized = subject.toSerialized();
private final Flowable<T> backpressureFlowable;
public SerializedBackpressureSubject(int bufferSize) {
this.backpressureFlowable = serialized
.toFlowable(BackpressureStrategy.BUFFER)
.onBackpressureBuffer(
bufferSize,
() -> System.out.println("Buffer overflow"),
BackpressureOverflowStrategy.DROP_OLDEST
);
}
public void emit(T item) {
serialized.onNext(item);
}
public Flowable<T> asFlowable() {
return backpressureFlowable;
}
}
// 3. 速率限制
public static class RateLimitedSubject<T> {
private final PublishSubject<T> subject = PublishSubject.create();
private final Observable<T> rateLimited;
private long lastEmitTime = 0;
public RateLimitedSubject(long minInterval, TimeUnit unit) {
this.rateLimited = subject
.filter(item -> {
long now = System.currentTimeMillis();
if (now - lastEmitTime >= unit.toMillis(minInterval)) {
lastEmitTime = now;
return true;
}
return false;
})
.share(); // 共享Observable
}
public void tryEmit(T item) {
subject.onNext(item);
}
public Observable<T> getStream() {
return rateLimited;
}
}
}
八、Subject内存管理
8.1、防止内存泄露
java
public class SafeSubjectUsage {
// 1. 使用弱引用订阅者
public static class WeakSubject<T> {
private final PublishSubject<T> subject = PublishSubject.create();
private final Map<Observer<? super T>, WeakReference<Observer<? super T>>> weakObservers =
new ConcurrentHashMap<>();
public Disposable subscribeWeak(Observer<? super T> observer) {
WeakReference<Observer<? super T>> weakRef = new WeakReference<>(observer);
weakObservers.put(observer, weakRef);
Disposable disposable = subject.subscribe(
item -> {
Observer<? super T> obs = weakRef.get();
if (obs != null) {
obs.onNext(item);
} else {
// 观察者已被GC,清理弱引用
weakObservers.remove(observer);
}
},
error -> {
Observer<? super T> obs = weakRef.get();
if (obs != null) {
obs.onError(error);
}
weakObservers.remove(observer);
},
() -> {
Observer<? super T> obs = weakRef.get();
if (obs != null) {
obs.onComplete();
}
weakObservers.remove(observer);
}
);
return new Disposable() {
@Override
public void dispose() {
disposable.dispose();
weakObservers.remove(observer);
}
@Override
public boolean isDisposed() {
return disposable.isDisposed();
}
};
}
public void onNext(T item) {
subject.onNext(item);
}
}
// 2. 自动清理的Subject
public static class AutoCleanupSubject<T> extends Subject<T> {
private final PublishSubject<T> delegate = PublishSubject.create();
private final CompositeDisposable disposables = new CompositeDisposable();
private final long timeout;
private final TimeUnit timeUnit;
public AutoCleanupSubject(long timeout, TimeUnit timeUnit) {
this.timeout = timeout;
this.timeUnit = timeUnit;
}
@Override
protected void subscribeActual(Observer<? super T> observer) {
Disposable disposable = delegate.subscribe(observer);
disposables.add(disposable);
// 设置超时自动清理
Disposable timeoutDisposable = Completable.timer(timeout, timeUnit)
.subscribe(() -> {
if (!disposable.isDisposed()) {
disposable.dispose();
disposables.remove(disposable);
}
});
disposables.add(timeoutDisposable);
}
@Override
public void onNext(T t) {
delegate.onNext(t);
}
@Override
public void onError(Throwable e) {
delegate.onError(e);
}
@Override
public void onComplete() {
delegate.onComplete();
}
@Override
public boolean hasObservers() {
return delegate.hasObservers();
}
public void cleanup() {
disposables.clear();
}
}
// 3. 使用CompositeDisposable管理订阅
public static class ManagedSubject<T> {
private final Subject<T> subject;
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
public ManagedSubject(Subject<T> subject) {
this.subject = subject.toSerialized(); // 线程安全
}
public Disposable subscribeManaged(Observer<? super T> observer) {
Disposable disposable = subject.subscribe(observer);
compositeDisposable.add(disposable);
return disposable;
}
public void emit(T item) {
subject.onNext(item);
}
public void disposeAll() {
compositeDisposable.clear();
}
public boolean isDisposed() {
return compositeDisposable.isDisposed();
}
}
}
8.2、Subject的引用计数
java
public class ReferenceCountedSubject<T> extends Subject<T> {
private final PublishSubject<T> delegate = PublishSubject.create();
private int refCount = 0;
private final Object lock = new Object();
@Override
protected void subscribeActual(Observer<? super T> observer) {
synchronized (lock) {
refCount++;
}
Disposable disposable = delegate.subscribe(observer);
return new Disposable() {
@Override
public void dispose() {
disposable.dispose();
synchronized (lock) {
refCount--;
if (refCount == 0) {
cleanup();
}
}
}
@Override
public boolean isDisposed() {
return disposable.isDisposed();
}
};
}
@Override
public void onNext(T t) {
delegate.onNext(t);
}
@Override
public void onError(Throwable e) {
delegate.onError(e);
}
@Override
public void onComplete() {
delegate.onComplete();
}
@Override
public boolean hasObservers() {
return delegate.hasObservers();
}
public int getRefCount() {
synchronized (lock) {
return refCount;
}
}
private void cleanup() {
// 清理资源
System.out.println("No more observers, cleaning up...");
}
}
九、Subject性能优化
9.1、高效事件分发
java
public class EfficientSubject<T> {
// 1. 使用数组存储观察者
public static class FastPublishSubject<T> extends Subject<T> {
private final List<Observer<? super T>> observers = new CopyOnWriteArrayList<>();
@Override
protected void subscribeActual(Observer<? super T> observer) {
observers.add(observer);
observer.onSubscribe(new Disposable() {
private volatile boolean disposed;
@Override
public void dispose() {
disposed = true;
observers.remove(observer);
}
@Override
public boolean isDisposed() {
return disposed;
}
});
}
@Override
public void onNext(T t) {
for (Observer<? super T> observer : observers) {
if (!((Disposable)observer).isDisposed()) {
observer.onNext(t);
}
}
}
@Override
public void onError(Throwable e) {
for (Observer<? super T> observer : observers) {
observer.onError(e);
}
}
@Override
public void onComplete() {
for (Observer<? super T> observer : observers) {
observer.onComplete();
}
}
@Override
public boolean hasObservers() {
return !observers.isEmpty();
}
}
// 2. 批处理事件
public static class BatchedSubject<T> extends Subject<T> {
private final PublishSubject<T> delegate = PublishSubject.create();
private final List<T> batchBuffer = new ArrayList<>();
private final int batchSize;
private final Scheduler scheduler;
public BatchedSubject(int batchSize, Scheduler scheduler) {
this.batchSize = batchSize;
this.scheduler = scheduler;
}
@Override
protected void subscribeActual(Observer<? super T> observer) {
delegate.subscribe(observer);
}
@Override
public void onNext(T t) {
synchronized (batchBuffer) {
batchBuffer.add(t);
if (batchBuffer.size() >= batchSize) {
emitBatch();
}
}
}
@Override
public void onError(Throwable e) {
emitBatch(); // 发射剩余数据
delegate.onError(e);
}
@Override
public void onComplete() {
emitBatch(); // 发射剩余数据
delegate.onComplete();
}
@Override
public boolean hasObservers() {
return delegate.hasObservers();
}
private void emitBatch() {
synchronized (batchBuffer) {
if (!batchBuffer.isEmpty()) {
List<T> batch = new ArrayList<>(batchBuffer);
batchBuffer.clear();
scheduler.scheduleDirect(() -> {
for (T item : batch) {
delegate.onNext(item);
}
});
}
}
}
}
}
9.2、零拷贝数据传输
java
public class ZeroCopySubject<T> {
public static class SharedBufferSubject<T> extends Subject<T> {
private final PublishSubject<BufferReference<T>> delegate = PublishSubject.create();
private final ThreadLocal<BufferReference<T>> threadLocalBuffer =
ThreadLocal.withInitial(BufferReference::new);
@Override
protected void subscribeActual(Observer<? super T> observer) {
delegate.subscribe(
bufferRef -> {
T data = bufferRef.getAndClear();
if (data != null) {
observer.onNext(data);
}
},
observer::onError,
observer::onComplete
);
}
@Override
public void onNext(T t) {
BufferReference<T> bufferRef = threadLocalBuffer.get();
bufferRef.set(t);
delegate.onNext(bufferRef);
}
@Override
public void onError(Throwable e) {
delegate.onError(e);
}
@Override
public void onComplete() {
delegate.onComplete();
}
@Override
public boolean hasObservers() {
return delegate.hasObservers();
}
static class BufferReference<T> {
private T data;
public void set(T data) {
this.data = data;
}
public T getAndClear() {
T temp = data;
data = null;
return temp;
}
}
}
}
十、常见问题解决方案
10.1、内存泄露问题
java
public class SubjectMemoryLeakSolutions {
// 问题:长期持有Observer引用
public static class LeakingSubject {
private final PublishSubject<Event> subject = PublishSubject.create();
private final List<Observer<Event>> observers = new ArrayList<>();
public void addObserver(Observer<Event> observer) {
observers.add(observer);
subject.subscribe(observer); // ❌ 订阅后持有observer引用
}
public void removeObserver(Observer<Event> observer) {
observers.remove(observer);
// ❌ 无法从subject取消订阅
}
}
// 解决方案1:使用CompositeDisposable
public static class SafeSubject1 {
private final PublishSubject<Event> subject = PublishSubject.create();
private final CompositeDisposable disposables = new CompositeDisposable();
public void addObserver(Observer<Event> observer) {
Disposable disposable = subject.subscribe(observer);
disposables.add(disposable);
}
public void removeAllObservers() {
disposables.clear();
}
}
// 解决方案2:使用WeakReference
public static class SafeSubject2 {
private final PublishSubject<Event> subject = PublishSubject.create();
private final Map<Observer<Event>, Disposable> observerMap =
new WeakHashMap<>();
public void addObserver(Observer<Event> observer) {
Disposable disposable = subject.subscribe(observer);
observerMap.put(observer, disposable);
}
public void removeObserver(Observer<Event> observer) {
Disposable disposable = observerMap.remove(observer);
if (disposable != null) {
disposable.dispose();
}
}
}
}
10.2、线程安全问题
java
public class SubjectThreadSafety {
// 问题:非线程安全的Subject
public static class UnsafeSubjectUsage {
private final PublishSubject<String> subject = PublishSubject.create(); // ❌ 非线程安全
public void emitFromMultipleThreads() {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
executor.submit(() -> {
subject.onNext("Data from " + Thread.currentThread().getId());
});
}
// 可能发生并发修改异常
}
}
// 解决方案:使用序列化Subject
public static class ThreadSafeSubject {
private final PublishSubject<String> subject =
PublishSubject.<String>create().toSerialized(); // ✅ 线程安全
public void emitFromMultipleThreads() {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
executor.submit(() -> {
subject.onNext("Data from " + Thread.currentThread().getId());
});
}
}
}
}
10.3、背压问题
java
public class SubjectBackpressure {
// 问题:快速生产者,慢速消费者
public static class BackpressureProblem {
private final PublishSubject<Integer> subject = PublishSubject.create();
public void causeBackpressure() {
// 快速生产
Observable.range(1, 1000000)
.subscribe(subject::onNext);
// 慢速消费
subject
.observeOn(Schedulers.io())
.subscribe(i -> {
Thread.sleep(10); // 慢速处理
System.out.println(i);
});
// ❌ 可能OOM
}
}
// 解决方案1:使用FlowableProcessor
public static class BackpressureSolution1 {
private final PublishProcessor<Integer> processor = PublishProcessor.create();
public void handleBackpressure() {
Observable.range(1, 1000000)
.subscribe(
processor::onNext,
processor::onError,
processor::onComplete
);
processor
.onBackpressureBuffer(1000) // 缓冲区
.observeOn(Schedulers.io())
.subscribe(i -> {
Thread.sleep(10);
System.out.println(i);
});
}
}
// 解决方案2:使用Subject + 背压策略
public static class BackpressureSolution2 {
private final PublishSubject<Integer> subject = PublishSubject.create();
public void handleBackpressure() {
Observable.range(1, 1000000)
.subscribe(subject::onNext);
subject
.toFlowable(BackpressureStrategy.DROP) // 背压策略
.observeOn(Schedulers.io())
.subscribe(i -> {
Thread.sleep(10);
System.out.println(i);
});
}
}
}
十一、最佳实践
11.1、选择正确的Subject类型
java
public class SubjectSelectionGuide {
public static Subject<?> selectSubject(UseCase useCase) {
switch (useCase) {
case EVENT_BUS:
// 事件总线:只需要实时事件
return PublishSubject.create().toSerialized();
case STATE_MANAGEMENT:
// 状态管理:需要当前状态
return BehaviorSubject.create().toSerialized();
case DATA_REPLAY:
// 数据重放:需要历史数据
return ReplaySubject.createWithSize(1000).toSerialized();
case ASYNC_RESULT:
// 异步结果:只需要最终结果
return AsyncSubject.create();
case SINGLE_CONSUMER:
// 单消费者:确保只有一个订阅者
return UnicastSubject.create();
case BACKPRESSURE_NEEDED:
// 需要背压:使用FlowableProcessor
return PublishProcessor.create();
default:
throw new IllegalArgumentException("Unknown use case");
}
}
enum UseCase {
EVENT_BUS,
STATE_MANAGEMENT,
DATA_REPLAY,
ASYNC_RESULT,
SINGLE_CONSUMER,
BACKPRESSURE_NEEDED
}
}
11.2、Subject的封装模式
java
public class SubjectWrapper<T> {
private final Subject<T> subject;
private final CompositeDisposable disposables = new CompositeDisposable();
private SubjectWrapper(Subject<T> subject) {
this.subject = subject.toSerialized(); // 自动序列化
}
public static <T> SubjectWrapper<T> publish() {
return new SubjectWrapper<>(PublishSubject.create());
}
public static <T> SubjectWrapper<T> behavior(T defaultValue) {
return new SubjectWrapper<>(BehaviorSubject.createDefault(defaultValue));
}
public static <T> SubjectWrapper<T> replay(int bufferSize) {
return new SubjectWrapper<>(ReplaySubject.createWithSize(bufferSize));
}
public Disposable subscribe(Observer<? super T> observer) {
Disposable disposable = subject.subscribe(observer);
disposables.add(disposable);
return disposable;
}
public void emit(T value) {
subject.onNext(value);
}
public void complete() {
subject.onComplete();
}
public void error(Throwable throwable) {
subject.onError(throwable);
}
public Observable<T> asObservable() {
return subject.hide(); // 隐藏Subject特性
}
public void disposeAll() {
disposables.clear();
}
public boolean hasObservers() {
return subject.hasObservers();
}
}