Working around the “variable might not have been initialized” error



public final void sendAdvertisement(final Advertisement advertisment, int delay, final int repetitions){
    final ScheduledFuture exec = executor.scheduleAtFixedRate( //<< initialized on this line
        new Runnable(){
            int totalSends = 0;
            public void run(){
                //do stuff here

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

If this isn’t possible, could you suggest a better way to do this? I couldn’t find a method for it in ScheduledThreadPoolExecutor. basically what I’m trying to do is make this code be run 3 times then cancel the “timer.” I could probably use Swing Timer, but I don’t want to since its used for other stuff.

It says in the comments, but this is the error:

%PATH%Discovery.java:148: variable exec might not have been initialized
                if(++totalSends >= repetitions) exec.cancel(true);

Answer

Your code may work from the standpoint of removing the compiler warning but the whole point of the warning is pointing out that you may be accessing a variable that has not been assigned yet. Even if exec or exec[0] is non-null there is also no guarantee that the ScheduledFuture object has even been properly initialized — yes even though the inner thread may be running. This is very dangerous and might work for a while but then fail dramatically in production, when you move to an architecture with more cores, or under different load circumstances. It also may work but then you change your do stuff here code a month from now and it starts to fail.

I see a couple of ways that you can accomplish this in a better manner. They are more complicated but also more safe and consistent with Java. The first that comes to mind is by using the AtomicReference:

// 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);


Source: stackoverflow