import java.util.Timer; 
import java.util.TimerTask; 
import javafx.application.Application; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.effect.DropShadow; 
import javafx.scene.effect.Effect; 
import javafx.scene.image.Image; 
import javafx.scene.image.ImageView; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 
import javafx.stage.WindowEvent; 

/** 
 * Demonstrate a memory leak on macOS 10.13.2 and Windows 8.1 Pro (running 
 * the same JDK [1.8.0_144]). 
 * @author Melkis Espinal 
 */ 
public class BlinkingMemoryLeak extends Application 
{ 
	Timer timer; 
	TimerTask timerTask; 
	Button btn = new Button("Click To Stop Animation"); 
	DropShadow ds = new DropShadow(); 
	@Override 
	public void start(Stage primaryStage) 
	{ 
		primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() 
		{ 
			@Override 
			public void handle(WindowEvent event) 
			{ 
				if(timer != null) 
				{ 
					timer.cancel(); 
					primaryStage.close(); 
					System.exit(0); 
				} 
			} 
		}); 
		//add alarm.png image for the button icon 
		//Image img = new Image(getClass().getResourceAsStream("alarm1.png"), 50, 50, true, true); 
		//ImageView iv = new ImageView(img); 
		//btn.setGraphic(iv); 

		StackPane root = new StackPane(); 
		root.getChildren().add(btn); 

		Scene scene = new Scene(root, 500, 500); 

		primaryStage.setTitle("Blinking Memory Leak"); 
		primaryStage.setScene(scene); 
		primaryStage.show(); 

		setupTimer(); 
	} 

	/** 
	 * Sets up timer and button listener on action to start or stop the timer. 
	 */ 
	public void setupTimer() 
	{ 
		timerTask = new TimerTask() { 
			@Override 
			public void run() 
			{ 
				Effect effect = btn.getEffect(); 
				if(effect == null) 
				{ 
					btn.setEffect(ds); 
				} 
				else 
				{ 
					btn.setEffect(null); 
				} 
				effect = null; 
			} 
		}; 
		timer = new Timer(); 
		timer.scheduleAtFixedRate(timerTask, 0, 100); 
		btn.setOnAction(new EventHandler<ActionEvent>() 
		{ 
			@Override 
			public void handle(ActionEvent event) 
			{ 
				btn.setEffect(null); 
				if(timer != null) 
				{ 
					timer.cancel(); 
					timer = null; 
				} 
				if(timerTask != null) 
				{ 
					timerTask.cancel(); 
					timerTask = null; 
				} 
			} 
		}); 
	} 

	/** 
	 * @param args the command line arguments 
	 */ 
	public static void main(String[] args) 
	{ 
		launch(args); 
	} 
} 
