实例变量在多线程行为

问题描述 投票:2回答:2

我想用4个线程运行的程序。我想知道有关实例变量的线程的行为。在此,我需要一个值传递给方法。所以,我做这样的传递价值,并用它进行进一步的处理。

@Component
class ThreadExample implements Runnable
{
    String file;

    public void setFile(String file)
    {
       this.file = file;
    }
    @override
    public void run()
    {
       readFile(file);
    }
    public void readFile(String fileName)
    {  
        //logic for reading file
    }
}

@component
class ThreadCall
{
    @Autowired
    ThreadExample ex;

     public void testThread()
     {
        ExecutorService executor2 = Executors.newFixedThreadPool(4);
        getFiles()
          .stream()
          .forEach(f-> {
               ex.setFile(f);
               executor2.submit(ex);                             
           });
     }

}

getFiles() API返回的文件名列表。我试图做到这一点在Spring。在这里,4个线程同时工作。对象exautowired所以它只能一次实例化。

如何file变量的值会降低?

我的想法一样,一个线程将尝试通过setFile(file)设置文件,它会被另一个线程readFile使用前进行更改。

如何解决这个问题?如何通过多线程中的值?请问如果我做“文件”作为volatile我的问题得到解决?

java spring multithreading
2个回答
2
投票

这里:

@Component
class ThreadExample implements Runnable
{
    String file;

    public void setFile(String file)

对象EX是自动装配,因此将只实例化一次。

这是行不通的。你有:

executor2.submit(ex);      

您传递相同的对象,都应该做具体在什么并行多任务。更糟的是,你把不同的值成单个对象,并神奇地希望每个任务正好看到你发给它看到价值。会发生什么:这些事情发生在不同的线程,这样的结果是(可能是)完全随机的,又名不确定的。

长话短说:当你有多个“东西”需要做的,随着时间的推移,你就不能使用“单类”容器派遣您的参数。 volatile不会与帮助,一点都没有。

答案是:为了使这项工作,ThreadExample不能是“单身”,使@Component注解,把它变成一个单必须走开。如果与其他的设计理念这样做“碰撞”,那么你必须退后一步,返工您的设计。


1
投票

你必须让ThreadExample为原型豆。

@Component
@Scope("prototype")
class ThreadExample implements Runnable
{
    String file;

    public void setFile(String file)
    {
       this.file = file;
    }
    @Override
    public void run()
    {
       readFile(file);
    }
    public void readFile(String fileName)
    {  
        //logic for reading file
    }
}

然后,而不是在ThreadCall注入ThreadExample豆你必须注入应用程序上下文:

@Component
class ThreadCall
{
    @Autowired
    ApplicationContext context;


     public void testThread()
     {
        ExecutorService executor2 = Executors.newFixedThreadPool(4);
        getFiles()
          .stream()
          .forEach(f-> {
            ThreadExample ex= context.getBean(ThreadExample.class);   
               ex.setFile(f);
               executor2.submit(ex);                             
           });
     }

}

当你调用这个代码,基本上每个ThreadExample将是一个新的bean。

© www.soinside.com 2019 - 2024. All rights reserved.