java示例变量在多线程中的行为

i2byvkas  于 2021-07-09  发布在  Java
关注(0)|答案(2)|浏览(232)

我正在尝试运行一个有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个线程将同时工作。对象 `ex` 是 `autowired` 所以它只会被示例化一次。
怎样 `file` 变量值会影响吗?
我在想,一个线程将试图通过设置文件 `setFile(file)` 在中使用它之前,它将被其他线程更改 `readFile` . 
如何克服这个问题?如何在多线程中传递值?如果我把“文件”做成 `volatile` ?
h5qlskok

h5qlskok1#

您必须将threadexample作为原型bean。

@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 bean:

@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。

jdgnovmf

jdgnovmf2#

在这里:

@Component
class ThreadExample implements Runnable
{
    String file;

    public void setFile(String file)


对象ex是自动连接的,因此它只会示例化一次。
那不行。您有:

executor2.submit(ex);

您将同一个对象传递给多个任务,这些任务应该并行执行特定的操作。更糟糕的是,您将不同的值推入到单个对象中,并以某种方式神奇地期望每个任务都能看到您希望它看到的值。会发生什么:这些事情发生在不同的线程上,所以结果(可能)是完全随机的,也就是不确定的。
长话短说:当您有多个“事情”需要完成时,随着时间的推移,就不能使用“类似单例”的容器来分派参数。 volatile 不会有帮助的,一点也不会。
答案是:为了让这一切顺利进行, ThreadExample 不能是“单例”,因此将其转换为单例的@component注解必须消失。如果这样做与您的其他设计思想“冲突”,那么您必须后退一步,重新设计您的设计。

相关问题