Java 弹簧DI的螺纹安全含义
在我设计的示例中,团队成员列表对线程安全有什么影响 我能否依靠Java 弹簧DI的螺纹安全含义,java,spring,dependency-injection,thread-safety,Java,Spring,Dependency Injection,Thread Safety,在我设计的示例中,团队成员列表对线程安全有什么影响 我能否依靠run()方法看到的列表状态保持一致 假定 spring在创建ATeamEpisodebean时只调用一次setATeamMembers方法 init方法由spring(init方法)在#1之后调用 ATeamMember类是不可变的 我是否需要声明团队成员易失性或类似情况 这种方法还有其他我所担心的可怕问题吗 俯瞰 如果这是明显的,或rtfm明显失败,则表示歉意 谢谢和问候 package-aTeam; 导入java.util
run()
方法看到的列表状态保持一致
假定
ATeamEpisode
bean时只调用一次setATeamMembers
方法init
方法由spring(init方法)在#1之后调用ATeamMember
类是不可变的
- 我是否需要声明
团队成员
或类似情况易失性
- 这种方法还有其他我所担心的可怕问题吗 俯瞰
package-aTeam;
导入java.util.ArrayList;
导入java.util.List;
导入java.util.Random;
公共类ATeamEpisode实现可运行{
私人名单小组成员;
/*春之地*/
public void setATeamMembers(列出团队成员){
this.teamMembers=newarraylist(teamMembers);
}
私有线程冲突线程;
公共同步的void init(){
System.out.println(“开始小冲突”);
破坏();
(小冲突线程=新线程(此为“小冲突线程”)).start();
}
公共同步的void destroy(){
if(小冲突线程!=null){
小冲突线程中断();
小冲突线程=null;
}
}
私人无效消防队(ATeamMember团队成员){
System.out.println(teamMember.getName()+“喷洒天空…”);
}
@凌驾
公开募捐{
试一试{
随机rnd=新随机();
而(!Thread.interrupted()){
fireswildlyintheair(teamMembers.get(rnd.nextInt(teamMembers.size()));
线程睡眠(1000*rnd.nextInt(5));
}
}捕捉(中断异常e){
System.out.println(“冲突结束”);
/*按照亚当的建议编辑*/
//Thread.currentThread().interrupt();
}
}
}
如您所说,如果setATeamMembers只被调用一次,并且您的代码中没有任何其他部分可以替代此集合,那么将其变为易失性是没有意义的。Volatile表示成员可以由不同的线程写入
<> P>考虑到您的代码中没有一部分似乎正在更新此集合,您可能需要考虑使集合显式不可修改,例如使用CytRun.UnMudiFabelEistIn()。这向您和其他人表明,此集合不会被修改,并且如果您尝试无论如何修改它,将在您的脸上抛出一个巨大的异常
Spring的惰性初始化是线程安全的 也许吧。
列表
接口本身不是线程安全的,无论您做什么,它都无法在用户端实现线程安全
您需要做的是创建一个线程安全列表(Java运行时有两个实现),并将其中一个用于teamMembers
bean
通过teamMembers
字段访问bean不是问题,因为其他线程不创建新实例,而是更改teamMembers
bean的状态(即内部数据)
因此bean必须确保对其内部结构的更改正确同步
在您的情况下,您将需要一个特殊的列表实现,它从列表中返回一个随机元素。为什么?因为调用teamMembers.get()
时,teamMembers.size()
的值可能已更改
实现这一点的一个简单方法是将所有方法调用包装在此代码中:
synchronized(teamMembers) { ... }
但你必须确定你真的抓住了他们。实现这一点最简单的方法是,正如我上面所说的,编写自己的列表,其中提供了您需要的所有特殊方法。这样,您可以根据需要在方法内部使用锁或
synchronized
。谁执行Runnable?谁打断了?通常,基于setter的注入遵循构造,因此我认为run()在这里是安全的。但是您的代码还有其他问题。例如,在线程被中断后调用Thread.currentThread().interrupt()。感谢Adam,有趣的一点,cf。在这里吞下异常可以吗?在从run()调用的子例程中,这是有意义的,它不能抛出checked InterruptedException,但不能直接在run()中抛出线程(runnable)应该存在的位置,因为您只想退出,所以他的代码没有任何部分会更新列表,所以这实际上不是问题,除非我们假设代码片段缺失。如果列表被更新,那么是的,呼叫应该被同步。@marb:最终,他将开始更新列表,然后,他将忘记在哪里使用了他应该用锁保护的呼叫。因此,最好确保他同步过多,直到他开始了解自己在做什么。