我正在尝试为正在构建的Android应用程序创建轻量,线程安全的应用程序内发布/订阅机制。我的基本方法是跟踪IEventSubscriber<T>每个事件类型T 的列表,然后能够通过传递类型T的有效负载来将事件发布到订阅对象。
我使用通用方法参数来(确保)确保以类型安全的方式创建订阅。因此,我非常确定,当我要从发布地图中获取订阅者列表时,是时候发布一个可以将其强制转换为的列表的事件了IEventSubscriber<T>,但是,这会生成未经检查的强制转换警告。
我的问题:
IEventSubscriber<T>?代码(Java 1.6):
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;
public class EventManager {
private ConcurrentMap<Class, CopyOnWriteArraySet<IEventSubscriber>> subscriptions =
new ConcurrentHashMap<Class, CopyOnWriteArraySet<IEventSubscriber>>();
public <T> boolean subscribe(IEventSubscriber<T> subscriber,
Class<T> eventClass) {
CopyOnWriteArraySet<IEventSubscriber> existingSubscribers = subscriptions.
putIfAbsent(eventClass, new CopyOnWriteArraySet<IEventSubscriber>());
return existingSubscribers.add(subscriber);
}
public <T> boolean removeSubscription(IEventSubscriber<T> subscriber,
Class<T> eventClass) {
CopyOnWriteArraySet<IEventSubscriber> existingSubscribers =
subscriptions.get(eventClass);
return existingSubscribers == null || !existingSubscribers.remove(subscriber);
}
public <T> void publish(T message, Class<T> eventClass) {
@SuppressWarnings("unchecked")
CopyOnWriteArraySet<IEventSubscriber<T>> …Run Code Online (Sandbox Code Playgroud) 在我之前的问题中,我正在做一个简单的练习,观察目录中的文件更改。我从这个 oracle docs 中获取了代码,它没有问题,除了我不确定的小未经检查的强制转换警告。
我对这段代码的下一个问题是它在线程中放置了一个硬循环,这至少在理论上是阻塞的。现在,我知道如果操作系统使用时间切片,即使是硬循环也会被分成小块,这些小块与应用程序正在运行的其他线程共享处理器的时间,事实上我可以制作各种硬循环的例子在不同的线程中运行不会互相阻塞(只要它们具有相同的优先级),即使是在一个明确创建的只有一个内核的虚拟机上。
但是,Java 语言不保证它使用哪种调度来管理线程,如果是时间片还是轮询;这取决于实际的 VM 实现和操作系统。所以我在学习这个主题时得到的建议是编写代码,就好像它必须在循环线程调度上运行一样,从而避免在线程中放置硬循环,除非我的代码可以不断地将控制权交还给其他线程与sleep()、wait()、yeld()等(我可以想到一个 GUI,其中主线程是一个硬循环监视事件,并将控制权发送回侦听器来处理它们的线程)。
但是,在我的情况下,我想不出一种方法在处理文件更改后让线程进入睡眠状态,或者将控制权返回主循环,因为核心思想基本上是不断询问是否有对文件系统的更改。所以我想到的是一个定期调用监视线程的预定执行程序。显然,这是在拥有“阻塞”线程和在发生文件系统更改时立即得到通知之间的权衡。由于在实际情况下我将进行此练习,因此我可能不需要立即通知,我对此很满意。代码非常简单:
// imports...
public class Main
{
public static FileSystem fs;
public static Path dir;
public static WatchService watcher;
public static WatchKey key;
public static void main(String[] args)
{
fs = FileSystem.getDefault();
dir = fs.getPath(".");
try {
watcher = fs.newWatchService();
dir.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
} catch (IOException e) {
System.err.println(e.getMessage());
return;
}
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable()
{
public void run()
{
Main.key = Main.watcher.poll(); …Run Code Online (Sandbox Code Playgroud)