1

When I start new thread in traditional constructor, NetBeansIDE gives no warnings:

addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {

        (new SomeThread()).start();
    }
});

But if I convert it to Lambda expression, I'm getting a warning "Starting new Thread in constructor":

addActionListener((ActionEvent e) -> {

   (new SomeThread()).start();
});

What is the problem here? What is the correct solution?

EDIT 1:

The same problem on NetBeans IDE 8.0.2:

enter image description here

The code:

import java.awt.event.ActionEvent;
import javax.swing.Timer;

public class TimerClass extends Timer {

    public TimerClass() {
        super(1000, null);//Loop 1 sec

        addActionListener((ActionEvent e) -> {

            (new SomeClass()).start();
        });

    }

    private class SomeClass extends Thread {

        @Override
        public void run() {

        }
    }
}
Ernestas Gruodis
  • 8,567
  • 14
  • 55
  • 117

1 Answers1

2

The problem here is that it's considered dangerous to start a thread or even register a listener in a constructor.

Explanation:
An inner class contains a reference to its enclosing class meaning that the thread that you started in your constructor has a reference to the TimerClass object's state before the constructor returned. So the new thread might see a partially constructed object with stale values (values that are current in one thread but not for others).

A simple fix:
Make the constructor private and then make a public and static factory method that creates the object and starts the thread.

import java.awt.event.ActionEvent;
import javax.swing.Timer;

public class TimerClass extends Timer {

    // notice that the constructor is now private.
    private TimerClass() {
        super(1000, null);  //Loop 1 sec
    }

    // This will create the instance and then register the listener and start the thread
    public static TimerClass createInstance() {

        TimerClass instance = new TimerClass();       
        instance.addActionListener((ActionEvent e) -> {

            (instance.new SomeClass()).start();
        });

        return instance;
    }

    private class SomeClass extends Thread {

        @Override
        public void run() {

        }
    }
}

With this, the thread will see a fully constructed object and thread safety will be restored (thus removing the warning).

Blazo
  • 194
  • 1
  • 7