Java 多线程中的实例变量行为
我正在尝试运行一个有4个线程的程序。我想知道线程中实例变量的行为。在这种情况下,我需要向方法传递一个值。因此,我这样做是为了传递值并将其用于进一步处理Java 多线程中的实例变量行为,java,spring,multithreading,Java,Spring,Multithreading,我正在尝试运行一个有4个线程的程序。我想知道线程中实例变量的行为。在这种情况下,我需要向方法传递一个值。因此,我这样做是为了传递值并将其用于进一步处理 @Component class ThreadExample implements Runnable { String file; public void setFile(String file) { this.file = file; } @override public void
@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
是自动连接的
,因此它将只实例化一次
文件
变量值会产生怎样的影响
我的想法是,一个线程将尝试通过setFile(file)
设置文件,在readFile
中使用它之前,它将被另一个线程更改
如何克服这个问题?如何在多线程中传递值?
如果我将“文件”设置为volatile,我的问题会得到解决吗?这里:
@Component
class ThreadExample implements Runnable
{
String file;
public void setFile(String file)
及
对象ex是自动连接的,因此它将只实例化一次 那不行。你有:
executor2.submit(ex);
您将相同的对象传递给多个任务,这些任务应该并行执行特定的任务。更糟糕的是,您将不同的值推入到单个对象中,并以某种方式神奇地期望每个任务都能准确地看到您希望它看到的值。将会发生什么:这些事情发生在不同的线程上,所以结果(可能)是完全随机的,也就是说是不确定的
长话短说:随着时间的推移,当您需要完成多个“事情”时,就不能使用“类似于单例”的容器来分派参数<代码>易失性对此没有帮助,一点也没有
答案是:为了实现这一点,
ThreadExample
不能是“单例”,因此将其转换为单例的@Component注释必须消失。如果这样做与您的其他设计思想“冲突”,那么您必须后退一步,重新设计您的设计 您必须将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。“Object ex是自动连接的,因此它将只实例化一次。”呃,不是真的。更准确地说,
ThreadExample
是一个组件,因此它只会被实例化一次。在您想做的事情和您想做的方式之间似乎存在逻辑上的不匹配。当您有一个线程池时,您通常希望提交多个新线程,而不是一个一次又一次提交的单线程,“…多个“线程”…”而不是使用scare引号,您可以这样称呼它们——多个可能由不同线程执行的任务。@SolomonSlow谢谢,说得好。相应地修改了答案。@GhostCat一个疑问,除了file
之外的每个变量都是readFile()
方法的局部变量。所以,我认为所有metod局部变量对于每个调用都是实例化的,即使对象ex
是单例的。唯一的问题是文件
。纠正我。谢谢你的回复。如果我在ThreadExample
中的Autowired
另一个对象是singleton并且应该是singleton,会发生什么。它的行为是否会像prototype
?是的,只要您将ThreadExample声明为prototype,并且使用应用程序上下文获取其实例,spring就会为ThreadExample提供新的对象。另外,在创建这个新对象的过程中,它将检查它的依赖关系,如果您已经自动连接了一个单例bean,那么它将把这个单例bean注入到原型bean中(在本例中是ThreadExample)。在我的上一个项目中,验证程序是原型&我在其中注入了单吨存储库。每次我从应用程序上下文询问验证程序的新实例时,spring也注入了repos