Spring DI的线程安全影响

时间:2012-10-08 11:46:57

标签: java spring dependency-injection thread-safety

在我设计的例子中,关于团队成员列表的线程安全有什么影响?

我可以依赖run()方法看到的列表状态来保持一致吗?

假设

  1. setATeamMembers方法只在春天创建ATeamEpisode bean时调用

  2. #{

  3. 后,init方法被spring(init-method)调用
  4. ATeamMember类是不可变的

    • 我是否需要声明teamMembers volatile或类似内容?

    • 这种方法还有其他任何可怕的问题吗? 俯瞰?

  5. 道歉,如果这是显而易见的,或明显失败的rtfm

    谢谢和问候

    package aTeam;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    
    public class ATeamEpisode implements Runnable{
    
        private List<ATeamMember> teamMembers;
    
        /* DI by spring */
        public void setATeamMembers(List<ATeamMember> teamMembers){
            this.teamMembers = new ArrayList<ATeamMember>(teamMembers);    
        }
    
        private Thread skirmishThread;
    
        public synchronized void init(){
            System.out.println("Starting skirmish");
            destroy();
            (skirmishThread = new Thread(this,"SkirmishThread")).start();
        }
        public synchronized void destroy(){
            if (skirmishThread != null){
                skirmishThread.interrupt();
                skirmishThread=null;
            }
        }
    
        private void firesWildlyIntoTheAir(ATeamMember teamMember){
            System.out.println(teamMember.getName()+" sprays the sky..");
        }
    
        @Override
        public void run() {
            try {
                Random rnd = new Random();
                while(! Thread.interrupted()){
                    firesWildlyIntoTheAir(teamMembers.get(rnd.nextInt(teamMembers.size())));
                    Thread.sleep(1000 * rnd.nextInt(5));
                }
            } catch (InterruptedException e) {
                System.out.println("End of skirmish");
                /* edit as per Adam's suggestion */
               // Thread.currentThread().interrupt();
            }
        }
    }
    

2 个答案:

答案 0 :(得分:5)

如果正如你所说的那样,setATeamMembers只被调用一次,并且代码的其他部分都没有替换这个集合,那么就没有必要让它变得不稳定。易失性表示成员可以被不同的线程书面

考虑到您的代码的任何部分似乎都没有更新此集合,您可能需要考虑使集合显式不可修改,例如通过使用Collections.unmodifiableList()。这让你和其他人清楚地知道,这个集合不会被修改,如果你试图修改它就会在你的脸上抛出一个很大的例外。

Spring的懒惰初始化是,AFAIR,线程安全。

答案 1 :(得分:3)

也许。这样的List接口不是线程安全的,无论你做什么,它都不能在消费者端使用

您需要做的是创建一个线程安全列表(Java运行时有几个实现)并使用其中一个用于teamMembers bean。

通过字段teamMembers访问bean不是问题,因为其他线程不创建新实例,它们会更改状态(即内部的数据) teamMembers bean。

因此bean必须确保对内部结构的更改正确同步。

在您的情况下,您将需要一个特殊的列表实现,它从列表中返回一个随机元素。为什么?因为调用teamMembers.size()teamMembers.get()的值可能已更改。

实现此目的的一种简单方法是在此代码中包装所有方法调用:

 synchronized(teamMembers) { ... }

但你必须确定你真的抓住了所有这些。实现这一目标的最简单方法是,如上所述,编写自己的列表,提供您需要的所有特殊方法。这样,您可以根据需要在方法内部使用锁或synchronized