[英]Accessing variable in a thread java
我的线程类中有一个全局变量,它是一个ArrayList<>
。 我定期从main()
方法运行此线程; 每当这个线程运行时,我在run()
方法中填充此列表。 我想从main()
方法访问此列表,但每当我从main()
访问此列表时,我都会得到一个空列表。 请建议我如何实现这一点,以下是我的代码示例。
private static ArrayList<SampleClass> allproxyDetailsPojoList = null;
public static void main(String[] args) {
try {
ScheduledExecutorService threadSchedulerService = Executors.newScheduledThreadPool(1);
threadSchedulerService.scheduleAtFixedRate(new SampleThreadClass(), 0, 5, TimeUnit.MINUTES);
Thread.sleep(8000);
SampleThreadClass sampleThreadClass = new SampleThreadClass();
// here i am getting list empty
allproxyDetailsPojoList = sampleThreadClass.getSampleClassList();
} catch (Exception e) {
}
}
这是我的线程类,
public class SampleThreadClass implements Runnable {
ArrayList<SampleClass> sampleClassList = null;
@Override
public void run() {
MyDao myDao = null;
try {
myDao = new MyDao();
sampleClassList = myDao.getSampleClassList();
} catch (Exception e) {
}
}
public ArrayList<SampleClass> getSampleClassList(){
return sampleClassList;
}
}
注意:不能使用static
关键字。
您需要了解类的哪些实例与类定义形成对比。 在您的代码中,您将创建该类的两个实例。 由于变量不是静态的,因此每个实例都有自己的变量实例。 您无法通过实例2的引用访问实例1的变量。
try {
ScheduledExecutorService threadSchedulerService = Executors.newScheduledThreadPool(1);
threadSchedulerService.scheduleAtFixedRate(new SampleThreadClass(), 0, 5, TimeUnit.MINUTES);
// ^ 1st Instance
Thread.sleep(8000);
SampleThreadClass sampleThreadClass = new SampleThreadClass(); // <-- 2nd Instance
因此,要使用单个实例,请将其更改为
try {
ScheduledExecutorService threadSchedulerService = Executors.newScheduledThreadPool(1);
SampleThreadClass sampleThreadClass = new SampleThreadClass();
threadSchedulerService.scheduleAtFixedRate(sampleThreadClass , 0, 5, TimeUnit.MINUTES);
Thread.sleep(8000);
但为了避免“奇怪的行为”,我还要同步访问sampleClassList
。
另外,为了避免NPE,我会改变
public ArrayList<SampleClass> getSampleClassList(){
return sampleClassList;
}
至
public ArrayList<SampleClass> getSampleClassList(){
if ( null != sampleClassList )
return sampleClassList;
return Collections.emptyList();
}
但请注意,这个空列表是不可变的。 如果你需要一个可变列表,你可以只返回一个new ArrayList<SampleClass>()
。
使用睡眠并不能使这段代码稳定。 如果您希望在等待服务调用至少执行一次后实际存在列表,则应该这样做而不是等待固定的时间段。 但这将是另一个问题。
您正在阅读您在其中创建的对象的列表
SampleThreadClass sampleThreadClass = new SampleThreadClass();
而不是你在这里创建并执行的那个:
threadSchedulerService.scheduleAtFixedRate(new SampleThreadClass(), 0, 5, TimeUnit.MINUTES);
这个
ArrayList<SampleClass> sampleClassList = null;
是一个实例变量,而不是全局变量。
我认为你得到一个空值而不是一个空列表。
一旦你创建了一个线程类的对象,你需要启动该线程。 可以使用start()
函数start()
线程。 当join()
函数与start()
一起使用时,主程序将等待你的线程执行。 线程完成执行后,主程序将开始运行。 如果你不使用join()
你的主程序将打印空的allproxyDetailsPojoList
,因为线程没有完成执行。
由于您正在使用执行程序服务,因此无需调用start()。 所以你就到了这里。 但是,您正在创建两个不同的SampleThreadClass。 第一个是在这里创建的:
ScheduledExecutorService threadSchedulerService = Executors.newScheduledThreadPool(1);
threadSchedulerService.scheduleAtFixedRate(new SampleThreadClass(), 0, 5, TimeUnit.MINUTES);
第二个是在这里创建的,执行者服务不知道这个,因为它从未传递给它。
SampleThreadClass sampleThreadClass = new SampleThreadClass();
这是如何解决:
SampleThreadClass sampleThreadClass = new SampleThreadClass();
ScheduledExecutorService threadSchedulerService = Executors.newScheduledThreadPool(1);
threadSchedulerService.scheduleAtFixedRate(sampleThreadClass, 0, 5, TimeUnit.MINUTES);
Thread.sleep(8000);
// here i am getting list empty
allproxyDetailsPojoList = sampleThreadClass.getSampleClassList();
在这个修复之后,接下来的事情是静态变量在线程中及时可见,它应该被定义为volatile。
在@ apadana
answer之上添加更多信息(保留同一个类的实例,已提交给ExecutorService
)
将任务提交到ExecutorService
,您的任务和主线程将并行运行。 在您的任务完成之前,主线程不会获得该值。 由于您在完成任务时访问变量,因此您将获得空值。
不要使用sleep来填充值。 而是依赖于ExecutorService invokeAll
API或使用CountDownLatch
看看工作代码示例:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.