【问题标题】:Is this code thread safe in a Spring application?此代码线程在 Spring 应用程序中是否安全?
【发布时间】:2015-01-21 11:33:10
【问题描述】:

使用 Ajax 请求从 .jsp 页面访问 ResourceMapping“过滤器”。

我的理解是Spring每次都会创建一个新的执行线程 访问资源“过滤器”。因为 FilterItems 是一个 Spring @Component bean 因此,如果是单例,那么多个线程(通过调用资源“过滤器”创建)将访问同一个实例。 每次调用“filter”时都会实例化一个新的 FilterItems 实例 资源,因为每个实例不在线程之间共享,所以这是线程安全的?

是调用 FilterItems.filter1 & FilterItems.filter2 线程安全?

@Controller
@RequestMapping("VIEW")
public class MyController {
@ResourceMapping(value = "filter") 
    public void filter(){

        FilterItems t = new FilterItems();
        LinkedList<MyObj> l = new LinkedList<MyObj>();
        l.add(new MyObj("1"));
        l.add(new MyObj("2"));

        System.out.println("size is : " + l.size());

        t.filterItem1(l);       
        System.out.println("size is : " + l.size());

        t.filterItem2(l);   
        System.out.println("size is : " + l.size());
    }
}

*****************************************************************************

import java.util.Iterator;
import java.util.LinkedList;

@Component
public class FilterItems {

    public void filterItem1(LinkedList<MyObj> l) {

        Iterator<MyObj> iter = l.iterator();
        while (iter.hasNext()) {
            MyObj myObj = iter.next();

            if (myObj.param.equalsIgnoreCase("1")) {
                iter.remove();
            }
        }
    }

    public void filterItem2(LinkedList<MyObj> l) {

        Iterator<MyObj> iter = l.iterator();
        while (iter.hasNext()) {
            MyObj myObj = iter.next();

            if (myObj.param.equalsIgnoreCase("2")) {
                iter.remove();
            }
        }
    }

    private static class MyObj {

        public final String param;

        public MyObj(String param) {
            this.param = param;
        }
    }

}

【问题讨论】:

    标签: java multithreading spring


    【解决方案1】:

    您的控制器代码不依赖于共享的可变数据,它只处理单个方法调用的本地数据。这意味着代码是线程安全的。

    不过,尚不清楚MyController 如何设法调用FilterItems 上的私有方法,或者它如何实例化一个外部私有静态类MyObj

    【讨论】:

    • 谢谢,我将方法调用的可见性改为公共而不是私有
    【解决方案2】:

    几乎是线程安全的,因为几乎所有数据都存储在局部变量中并作为参数传递。

    唯一可能的例外是MyObjparam字段,它应该是final,以保证创建对象后每个人都能看到相同的值。

    来自JLS

    一个对象被认为是完全初始化的,当它 构造函数完成。只能看到对 保证该对象完全初始化后的对象 查看该对象最终的正确初始化值 字段。

    但只要MyObj 类保持private 并且没有其他人可以实例化它们,那将不是问题。

    【讨论】:

    • 就此而言,他使用的LinkedList 也是可变的,但这不会在他的特定代码中造成问题。
    • @MarkoTopolnik 是的,它只是作为局部变量创建并作为参数传递,因此任何其他线程都看不到它。
    • 这与MyObj 实例有何不同?我错过了什么明显的东西吗?
    • @MarkoTopolnik 是的,你是对的,我错过了 MyObj 类被声明为 private 的事实。我认为理论上它们也可以由其他人实例化。我更新了我的答案。
    • 再一次,LinkedList 是一个公共的、可变的、线程不安全的类,但这不会使其在 OP 的特定代码中的使用出现问题。引发MyObj 问题的答案也必须引发FilterItems 方法的问题,因为它们会改变线程不安全的对象,并且在使用与发布内容不同时可能会导致线程安全问题。我的意见是,在这种情况下不应考虑此类考虑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多