Java 围绕",;变量可能尚未初始化";错误

Java 围绕",;变量可能尚未初始化";错误,java,multithreading,timer,threadpool,Java,Multithreading,Timer,Threadpool,基本上,我知道有两种方法可以解决这个问题。不幸的是,它们都不是特别好的结果代码质量,所以我不确定我是否可以推荐它们 第一个解决方案是使exec成为最终的单元素数组。然后,即使数组本身是最终的,您也可以在声明之后分配exec[0]=某些内容。一种变体是使用/创建一些引用类(因为您可以更改最终引用的属性,但不能更改引用本身)。下面是一个简单的示例,但请记住,它没有考虑任何并发问题(请参阅下文): final ScheduledFuture[]exec=new scheduledfrature[1];

基本上,我知道有两种方法可以解决这个问题。不幸的是,它们都不是特别好的结果代码质量,所以我不确定我是否可以推荐它们

第一个解决方案是使exec成为最终的单元素数组。然后,即使数组本身是最终的,您也可以在声明之后分配exec[0]=某些内容。一种变体是使用/创建一些引用类(因为您可以更改最终引用的属性,但不能更改引用本身)。下面是一个简单的示例,但请记住,它没有考虑任何并发问题(请参阅下文):

final ScheduledFuture[]exec=new scheduledfrature[1];

exec[0]=执行者。scheduleAtFixedRate(//=重复次数)exec[0]。取消(true)// 当您知道执行次数时,为什么要使用固定速率scheduer, 我认为simple for loop可以完成这项工作

    final ScheduledFuture[] exec = new ScheduledFixture[1];
    exec[0] = executor.scheduleAtFixedRate( //<< initialized on this line
            new Runnable(){
                int totalSends = 0;
                public void run(){
                    //do stuff here

                    if(++totalSends >= repetitions) exec[0].cancel(true); //<< here is says exec might not be initialized
                }
            },
        0, delay, TimeUnit.MILLISECONDS);
for(int i=0;i

正如WalterM所说:这不是创建许多新实例的好方法,在循环中使用引用。

从删除编译器警告的角度来看,您的代码可能可以工作,但警告的要点是指出您可能正在访问一个尚未赋值的变量。即使
exec
exec[0]
为非空,也不能保证
ScheduledFuture
对象已正确初始化——即使内部线程可能正在运行,也是如此。这是非常危险的,可能会工作一段时间,但在生产中,当您移动到具有更多内核的体系结构时,或者在不同的负载情况下,会显著失败。它也可以工作,但是从现在开始一个月后,你改变你的
在这里做的事情
代码,它开始失败

我认为有几种方法可以更好地实现这一点。它们更复杂,但也更安全,与Java保持一致。首先想到的是使用原子参考

for (int i = 0; i < iterations; i++) {
    executor.schedule(new Runnable() {
        public void run() {
            // do stuff here
        }
    }, delay * i, TimeUnit.MILLISECONDS);
}
//此类处理原子更新和内存同步
最终原子参考未来参考=
新原子引用();
ScheduledFuture exec=executor.scheduleAtFixedRate(
新的Runnable(){
整数=0;
公开募捐{
//在这里做事
如果(++totalSends>=重复次数){
//我们需要等待未来的开始
while(true){
ScheduledFuture future=futureReference.get();
如果(未来!=null){
future.cancel(true);
打破
}
试一试{
睡眠(1);
}捕捉(中断异常e){
线程。当前线程。(.interrupt();
}
}
}
}
},
0,延迟,时间单位为毫秒);
//这将设置将来的引用,以便线程可以使用它
futureference.set(exec);

final ScheduledFeature exec=null;exec=executor.sche。。。然后在if(++totalSends)语句中,添加一个辅助语句if(exec!=null){exec.cancel(true);}???这是不可能的,在初始化后不能更改最终变量,甚至不能更改为null,对吗。让它成为非最终答案。不管怎样,我删除了我的答案,我错了。如果将其设置为非final,则无法在runnable中访问它。我的不好,不过一定很有趣,否则我赢了;I don’我不能在不规则的内心课堂上使用它。谢谢,这是有道理的。我使用了大小为1的数组,因为我希望它只是方法的局部数组。可能它不会为null,因为线程需要一点时间才能运行,但我理解为什么会发生这种情况。所以我会考虑到这一点。对不起,我真的不同意这个答案。它可以解决编译问题,但不存在
exec[0]
不为null的问题,即使它不为null,对象也可能没有被完全初始化——即使
Runnable
正在运行。这是一种解决方案,它可能工作得很好,但在生产中,在不同的负载下,或者在更改了
do stuff here
中的工作量后,可能会失败。这就是为什么我在最后一段的第二段中特别警告了此类问题。诚然,按照您的建议使用原子引用肯定在各方面都要好得多。我不知道我怎么会忽略这个类这么长时间。这是个好主意,但我不想为每个迭代创建一个新的可运行类。特别是如果它可能超过10或更多。这太过分了。现在我想起来了,你的话实际上有一半是对的。如果在循环之前创建Runnable,然后在每次迭代中传递相同的Runnable对象。你实际上不需要新的。是的,当然-我的目标是执行问题,而不是创建多个实例的问题。你最终是如何解决这个问题的?是的,这几乎是一样的,我检查了(exec[0]==null);就我个人而言,我认为他们是一样的。我永远不会使用线程;但是在线程池中。我觉得这是个坏主意。
==null
不是一回事,伙计。优化器可以从初始值设定项返回一个值,但选择稍后执行实际的代码初始化。这与双重检查锁定bug是一样的:就睡眠而言,我个人认为旋转比睡眠危险得多。如果您真的需要,您可以执行
sleep(1)
。@WalterM请记住
sleep(1)
仅用于解决争用条件问题,因此很少会被命中。不,在使用它之前检查它是否为null是可以的,如果(exec[0]==null)exec[0]=ne,我不会这样做
    final ScheduledFuture[] exec = new ScheduledFixture[1];
    exec[0] = executor.scheduleAtFixedRate( //<< initialized on this line
            new Runnable(){
                int totalSends = 0;
                public void run(){
                    //do stuff here

                    if(++totalSends >= repetitions) exec[0].cancel(true); //<< here is says exec might not be initialized
                }
            },
        0, delay, TimeUnit.MILLISECONDS);
for (int i = 0; i < iterations; i++) {
    executor.schedule(new Runnable() {
        public void run() {
            // do stuff here
        }
    }, delay * i, TimeUnit.MILLISECONDS);
}
// this class handles atomic updates and memory synchronization
final AtomicReference<ScheduledFuture> futureReference =
    new AtomicReference<ScheduledFuture>();
ScheduledFuture exec = executor.scheduleAtFixedRate(
    new Runnable() {
        int totalSends = 0;
        public void run() {
            //do stuff here
            if (++totalSends >= repetitions) {
                // we need to wait for the future to be initialized
                while (true) {
                    ScheduledFuture future = futureReference.get();
                    if (future != null) {
                        future.cancel(true);
                        break;
                    }
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        Thread.currentThread.().interrupt();
                    }
                }
            }
        }
    },
    0, delay, TimeUnit.MILLISECONDS);
// this sets the future reference so the thread can use it
futureReference.set(exec);