在java线程中访问变量
我的thread类中有一个全局变量,它是在java线程中访问变量,java,multithreading,Java,Multithreading,我的thread类中有一个全局变量,它是ArrayList。我定期从main()方法运行此线程;每当此线程运行时,我都在run()方法中填充此列表。我想从main()方法访问此列表,但无论何时从main()访问此列表,我都会得到一个空列表。请建议我如何实现这一点,下面是我的代码示例 private static ArrayList<SampleClass> allproxyDetailsPojoList = null; public static void main(Stri
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) {
}
}
私有静态ArrayList allproxyDetailsPojoList=null;
公共静态void main(字符串[]args){
试一试{
ScheduledExecutorService threadSchedulerService=执行者。newScheduledThreadPool(1);
threadSchedulerService.scheduleAtFixedRate(新的SampleThreadClass(),0,5,TimeUnit.MINUTES);
睡眠(8000);
SampleThreadClass SampleThreadClass=新的SampleThreadClass();
//在这里,我得到的名单是空的
allproxyDetailsPojoList=sampleThreadClass.getSampleClassList();
}捕获(例外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;
}
}
公共类SampleThreadClass实现可运行{
ArrayList sampleClassList=null;
@凌驾
公开募捐{
MyDao MyDao=null;
试一试{
myDao=新的myDao();
sampleClassList=myDao.getSampleClassList();
}捕获(例外e){
}
}
公共ArrayList getSampleClassList(){
返回sampleClassList;
}
}
注意:不能使用
static
关键字。一旦创建了thread类的对象,就需要启动线程。可以使用start()
函数启动线程。
当join()
函数与start()
一起使用时,主程序将等待线程执行。线程完成执行后,主程序将开始运行。
如果不使用
join()
主程序将打印AllProxyDetailsJolist
,该列表为空,因为线程未完成执行 您正在读取在中创建的对象的列表
SampleThreadClass sampleThreadClass = new SampleThreadClass();
而不是您在此处创建并执行的:
threadSchedulerService.scheduleAtFixedRate(new SampleThreadClass(), 0, 5, TimeUnit.MINUTES);
这个
ArrayList sampleClassList=null;
是实例变量,而不是全局变量
我认为您得到的是一个空值,而不是一个空列表。您不需要调用start(),因为您使用的是executor服务。那么你就到这里来了。但是,您正在创建两个不同的SampleThreadClass。第一个是在这里创建的:
ScheduledExecutorService threadSchedulerService = Executors.newScheduledThreadPool(1);
threadSchedulerService.scheduleAtFixedRate(new SampleThreadClass(), 0, 5, TimeUnit.MINUTES);
第二个是在这里创建的,executorservice不知道这个,因为它从未被传递给它
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 您需要了解与类定义相比,类的实例是什么。在代码中,您创建了该类的两个实例。因为变量不是静态的,所以每个实例都有自己的变量实例。无法通过实例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
但是为了避免“奇怪的行为”,我还同步访问sampleClassList
另外,为了避免NPE,我会改变
public ArrayList<SampleClass> getSampleClassList(){
return sampleClassList;
}
public ArrayList getSampleClassList(){
返回sampleClassList;
}
到
public ArrayList getSampleClassList(){
if(null!=sampleClassList)
返回sampleClassList;
返回集合。emptyList();
}
但请记住,这个空列表是不可变的。如果您需要一个可变列表,只需返回一个新的ArrayList()
附笔。
使用睡眠并不能真正使代码稳定。如果在等待服务调用至少执行一次之后,您希望列表实际存在,那么您应该这样做,而不是等待固定的时间段。但那将是另一个问题。在@
apadana
答案上添加更多信息(保留已提交给ExecutorService
的类的相同实例)
一旦您将任务提交到ExecutorService
,您的任务和主线程将并行运行。在任务完成之前,主线程不会获取该值。由于您在未完成任务的情况下访问变量,因此得到的是空值
不要使用睡眠填充值。而是依赖于invokeAll
API或使用
查看工作代码示例:
他可以永远等待,因为他从与填充的实例不同的实例获取列表。实际上,他应该使用已提交给ExecutorService的相同实例。他正在创建一个不必要的实例。他正在使用同一个类。他使用的不是同一个实例。这些术语的使用不准确是导致新手犯此类错误的原因。我指的是实例。谢谢你给我一个改变来纠正我的评论。
try {
ScheduledExecutorService threadSchedulerService = Executors.newScheduledThreadPool(1);
SampleThreadClass sampleThreadClass = new SampleThreadClass();
threadSchedulerService.scheduleAtFixedRate(sampleThreadClass , 0, 5, TimeUnit.MINUTES);
Thread.sleep(8000);
public ArrayList<SampleClass> getSampleClassList(){
return sampleClassList;
}
public ArrayList<SampleClass> getSampleClassList(){
if ( null != sampleClassList )
return sampleClassList;
return Collections.emptyList();
}