java - 我可以将 AspectJ 用于 "wrap"一个带有 ThreadLocal 的字段吗?

标签 java thread-safety aspectj

假设我们有一个如下所示的类。

public class MyClass {

   @ThreadScoped    
   private Collection<String> words = new ArrayList<String>();

   public void addWord(String word) {
        words.add(word);
   }

}

在运行时,我们只有一个此类的实例,但它接受来自多个线程的调用。

我希望编写类的开发人员能够忽略他们正在为多线程访问编写类的事实,而只是将字段注释为“线程作用域”。

是否可以创建一个方面,使每个调用线程都有自己的单词集合,就好像单词字段本来是一个 ThreadLocal 一样?即使在方法的多次调用中,集合也应该绑定(bind)到线程。

我已经看到了 setget 切点,但是想不出一种不需要我在对象上设置字段的方法来使用它们,这会破坏类的线程安全。

是否有另一种不使用方面的方法,例如使用代理或反射?

最佳答案

您的设计中似乎有几个可能相互冲突的决定:

  • 您只有一个 MyClass 实例。

  • 您希望每个线程查看其自己版本的 words 字段。

在我看来,为此目的使用 AspectJ 可能有点矫枉过正。我想线程特定的访问可以被认为是一个横切关注点,但我不确定 AOP 是处理这个问题的方法。在尝试 AspectJ 之前,我会首先考虑重新设计纯 Java 代码。

老实说,我认为实现第二个效果的最简单方法是让每个线程都有自己的 MyClass 实例。如果不能将它显式传递给每个线程,您甚至可以使用 ThreadLocal 来提供对适当的 MyClass 实例的访问。

如果 MyClass 中有多个线程共享的字段,那么您可能需要考虑重构 MyClass 以将其分为两个类。这会将特定于线程的字段与共享字段分开,允许您以不同的方式处理每种情况。

编辑:

我仔细考虑了您的意见,在我看来,您正在尝试使用 AOP 从本质上向您的开发人员隐藏该字段的实现。编程接口(interface)与实际实现分离的问题在面向对象编程中大多已得到解决,而没有解决到 AOP。

在您的情况下,方法是使用 MyClass 的抽象父类(super class)来保存该字段的 private 声明,然后使用几个 getter 和 setter让 MyClass 使用它的方法。这样您就可以在不影响任何其他内容的情况下更改实际实现。

public abstract AbstractMyClass {
    private ... words = ...;

    protected Collection<String> getWords() {
        ...
    }
}

public Myclass extends AbstractMyClass {
   public void addWord(String word) {
        this.getWords().add(word);
   }
}

关于java - 我可以将 AspectJ 用于 "wrap"一个带有 ThreadLocal 的字段吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15117658/

相关文章:

java - 在线程之间共享变量时如何避免并发错误?

Java - 不可变数组线程安全

java - AspectJ、SpringAOP、Aspect 运行两次

java - 如何在销售员计划中返回销售额最高的人员-JAVA

java - XSL 多列切换

c++ - 线程安全函数指针 gsl 蒙特卡洛积分

java - 具有特定父类的切入点匹配类型

java - Spring:检查当前拦截器

java - 是否可以使用 KafkaIO.read 为单个管道的两个不同集群指定 Kafka 引导服务器?

JavaFx 组合框下拉列表宽度在第一次单击组合框时较小