java - 我编写的这些类在线程安全方面是否有问题?另外,ManagedBeans 是否在不同的线程中使用?

标签 java spring multithreading jsf thread-safety

我在这里写了这个类

@Component
public class LoginDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public List<Map<String, Object>> getUser(final String username, final String password) {
        return jdbcTemplate.queryForList("select * from users where username=? and password=?", new Object[]{username, password});
    }
}

现在,它由 JSF 中的托管 bean 使用,它只是在发出请求时创建和使用的 bean(如果使用默认范围)。

@ManagedBean
public class Login implements Serializable {
    @ManagedProperty("#{loginDao}")
    private LoginDao loginDao;
//..do something with loginDao
}

我担心这完全被破坏了,因为如果当 JSF 创建的 Login bean 去使用那个 LoginDao(它是一个注入(inject)对象)时,并且看到 LoginDao 的字段 jdbcTemplate 为空怎么办?

如果用于处理请求的 Login bean 将在单独的线程中运行(如果 Web 服务器使用该单独的线程来处理该请求),并且由于 LoginDao 的字段 jdbcTemplate 不是最终的并且在构造函数中设置,则可能会发生这种情况运行 Login bean 时,jdbcTemplate 在 Login 实例中不能被视为 null 吗?解决这个问题的方法是使 jdbcTemplate 变得不稳定吗?

而且,现在这让我开始质疑我用 spring 和 JSF 编写的所有内容。使用 @Autowired 注释时是否不可能编写线程安全的类,除非在该字段上使用 volatile 关键字?

我现在真的很担心使用依赖注入(inject)框架。我的意思是,是否可以保证容器注入(inject)的对象不会被视为空引用或处于非最新状态?

最佳答案

Autowiring bean 是在初始化期间注入(inject)的,因此在这种情况下,jdbcTemplate 在处理请求时决不应该为 null。但是,如果您想完全确定,可以通过构造函数注入(inject)它,这是推荐的方法:

@Component
public class LoginDao {

    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public LoginDao(JdbcTemplate jdbcTemplate) {
      this.jdbcTemplate = jdbcTemplate;
    }

    public List<Map<String, Object>> getUser(final String username, final String password) {
        return jdbcTemplate.queryForList("select * from users where username=? and password=?", new Object[]{username, password});
    }
}

正如您所说,多个请求很可能由不同的线程处理,并且会发生什么完全取决于定义的范围:

  • Spring 中的默认作用域是“singleton”,因此在这种情况下,LoginDAO 在应用程序中将只有一个实例来服务所有请求。在您发布的代码中,这不是问题,因为 JdbcTemplate 是线程安全的。

Also, now this makes me question everything I ever wrote with spring and JSF. Is it impossible to write thread-safe classes when using the @Autowired annotation unless you use the volatile keyword on that field?

完全有可能。这主要取决于您的需要。您可以拥有一个以线程安全方式执行其操作的单例 bean(取决于您的代码和您使用的库),或者您可以让非线程安全 bean 与“请求范围”一起工作(即:一个 bean 实例对于每个请求),或中间的任何内容(spring中有5种范围类型)。

如果出于完全不同的目的,则将字段设置为 volatile 。 volatile 关键字表示字段值将被多个线程不断修改,因此 JVM 不会将其值缓存在线程内以防止竞争条件,并且将以原子方式管理分配。这只会保护字段值,但如果该值是一个对象,则不会保护该对象内部的值。

I am really worried about using a dependency injection framework now. I mean, is there even a guarantee that objects that were injected by the container will not be seen as null for its reference or in a non up to date state?

至少根据我使用 Spring 的经验,我从未遇到过这个问题。 Spring 在初始化和启动时准备一切方面做得非常好,因此您不必担心这一点。但是,建议使用前面指出的构造函数 Autowiring 方法,因为这可以让程序员对您的问题更加安全。

关于java - 我编写的这些类在线程安全方面是否有问题?另外,ManagedBeans 是否在不同的线程中使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48019833/

相关文章:

java - Facebook sdk 图片发布失败

java - Spring Java Maven项目+模块设计

java - 自定义身份验证过滤器 Spring Security 3.2

java - hibernate查询在java spring中不起作用

即使使用 SwingWorker,Java GUI 也会卡住

java - QtWebkit 多线程

c++ - 什么时候出队大小调用不是线程安全的?

java - 在 String 中的特定位置查找模式并将其替换为 Java 中的其他内容

java - Android Studio 构建错误提示 JVM 版本

java - Spring MVC 将 HTTP POST 请求转发到另一个 Controller 中的 GET 请求处理程序