I'm trying to make a program that generates random numbers if the user presses a button. It should stop generating them, when the user presses the button the second time, and then it should print all the random numbers added together and the average random number, but I don't know how I should do this. When I'm in the loop i can't press the button. I'll be thankful for any help. My Code:
package Test;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Average
{
static int sizeX = 200;
static int sizeY = 200;
static int maxNum = 100;
static int minNum = 1;
static boolean running = true;
static JButton b1 = new JButton("Click me");
static void JFrame()
{
Toolkit tk = Toolkit.getDefaultToolkit();
Dimension dim = tk.getScreenSize();
JFrame f = new JFrame("Test");
f.setSize(sizeX, sizeY);
f.setVisible(true);
f.setLocation((dim.width - sizeX) / 2, (dim.height - sizeY) / 2);
f.setResizable(false);
f.setAutoRequestFocus(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(b1);
}
static void ActionListener()
{
b1.addActionListener(new ActionListener()//ActionListener
{
public void actionPerformed(ActionEvent e)//Execute when button is pressed
{
int numsGenerated = 0;
double ave = 0;
if (running == true)
{
while (true)
{
double r = Math.random() * (maxNum - minNum) + minNum; //(maxNum - minNum) + minNum
numsGenerated++;
ave = ave + r;
System.out.println("Random: " + r);
if (!running)
{
break;
}
}
running = false;
}
else
{
System.out.println("");
System.out.println("All: " + ave);
System.out.println("Average: " + ave / numsGenerated);
running = true;
}
}
}); //ActionListenerEnd
}
public static void main(String[] args)//Main
{
JFrame();
ActionListener();
}
}
As Ordous told in a comment, you should make a different thread for this work. But you may need to synchronize on "running" variable to make sure it works always.
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Average
{
static Object lock=new Object();
static int sizeX = 200;
static int sizeY = 200;
static int maxNum = 100;
static int minNum = 1;
static boolean running = false;
static JButton b1 = new JButton("Click me");
static void JFrame()
{
Toolkit tk = Toolkit.getDefaultToolkit();
Dimension dim = tk.getScreenSize();
JFrame f = new JFrame("Test");
f.setSize(sizeX, sizeY);
f.setVisible(true);
f.setLocation((dim.width - sizeX) / 2, (dim.height - sizeY) / 2);
f.setResizable(false);
f.setAutoRequestFocus(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(b1);
}
public class Thr extends Thread
{
#Override
public void run()
{
int numsGenerated = 0;
double ave = 0;
synchronized(lock)
{
running=!running;
}
if (running == true)
{
while (true)
{
double r = Math.random() * (maxNum - minNum) + minNum; //(maxNum - minNum) + minNum
numsGenerated++;
ave = ave + r;
System.out.println("Random: " + r);
synchronized(lock)
{
if (!running)
{
break;
}
}
}
synchronized(lock)
{
running = false;
}
}
System.out.println("");
System.out.println("All: " + ave);
System.out.println("Average: " + ave / numsGenerated);
running = true;
}
}
static Thr thread=null;
static void ActionListener()
{
b1.addActionListener(new ActionListener()//ActionListener
{
public void actionPerformed(ActionEvent e)//Execute when button is pressed
{
Average av=new Average();
if(thread==null)
{
thread=av.new Thr(); // should add in an executor
thread.start();
}
else
{
synchronized(lock)
{
running=false;
}
}
}
}); //ActionListenerEnd
}
public static void main(String[] args)//Main
{
JFrame();
ActionListener();
}
}
To have a simple thread, "Thread" is inherited and run() methoud must be overridden to use it. (you can use a "Runnable" instead of this too)
public class Thr extends Thread
{
#Override
public void run()
{
}
}
You start it like
threadName.Start()
or
ExecutorObject.submit(threadName);
where executor object has a pool for threads to run efficiently and is created by executor service.
Do not start threads with
threadname.run()
directly.
Also inter-thread communication is important. One thread leaves a message to somewhere, another thread reads. If there is no synchronization, they can race for the variable's visibility and wrong output can happen.
You can have an object to lock on.
synchronized(lock)
{
}
so this block can be entered by only single thread until it exits from this block. You should leave a message for other threads, to say "its ready" and wake them up(iff they are waiting) with
synchronized(lock)
{
lock.notifyAll();
}
then make the message-leaving thread (current thread) go on a waiting state so other threads can wake it up and let it exit the block.
synchronized(lock)
{
lock.notifyAll();
lock.wait();
}
but this alone is not enough because current thread accidentally exit the waiting state so you may force it to keep waiting:
synchronized(lock)
{
lock.notifyAll();
while(condition)
lock.wait();
}
if you make sure only a single thread can access a variable at a time, you can use it to communicate with other threads.
You can use some other ways to have barriers to synchronize all threads on a point so no threads can continue until all hit the same barrier. More communication can decrease overall performance.
Main program is a thread too, so it can wait, notify and synchronize.
Related
I have to make a DieTester for school. One that rolls the dice 100 times and then puts the output in a Table Chart and another table.
The problem is that my Thread wont sleep with the time that is set by the Slider.
Here my DieTester:
package sample.Controllers;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.RunnableFuture;
public class DieTester implements Runnable{
private Thread t;
private String Threadname;
List<Integer> List = new ArrayList();
Random rand = new Random();
long l;
public DieTester(String name){
Threadname = name;
}
public void run() {
for (int n = 0; n < 100; n++) {
try {
Thread.sleep(getTime());
List.add(rand.nextInt(6) + 1);
System.out.println(List.get(n));
} catch (InterruptedException e) {
System.out.println("Error");
}
}
}
public void start(){
if (t == null)
{
t = new Thread (this, Threadname);
t.start ();
}
}
public void setTime(double SliderTime){
l = (long) SliderTime;
}
public long getTime(){
return l;
}
}
Here the controller:
package sample.Controllers;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Slider;
public class Controller {
DieTester dice = new DieTester("Time");
double time=0;
EventHandler e = new EventHandler() {
#Override
public void handle(Event event) {
time = TimeSlider.getValue();
}
};
#FXML
Slider TimeSlider = new Slider(50, 2000, 50);
#FXML
public void HandlePauseResumeAction(){
}
#FXML
public void HandleStartAction(){
DieTester die = new DieTester("Start");
die.start();
}
#FXML
public void HandleSlider(){
TimeSlider.valueProperty().addListener((observable, oldValue, newValue) -> {
time = TimeSlider.getValue() * 20;
//System.out.println(time);
dice.setTime(time);
});
System.out.println(dice.getTime());
}
}
The slider and everything is set up properly. And if I call the getTime() it puts out the time properly, but the Thread isn't sleeping or something.
This is a mutable shared variable :
long l
Threads access it concurrently, (one reads, one writes), yet it doesn't have proper synchronization, so writes of one thread are not guaranteed to be seen by the other thread.
On top of that, l is initialized to 0, and odds are the spawned thread has raced through 100 loops, without really sleeping, before the first property change event happens.
Ok guys so I figured it out, this is what I did
#FXML
public void HandleStartAction(){
start();
}
public void run(){
for(int n = 0; n < 100; n++){
try {
if(!suspend){
Thread.sleep((long)TimeSlider.getValue() * 20);
List.add(rand.nextInt(6) + 1);
System.out.println(List.get(n));
}else{
}
} catch (InterruptedException e) {
System.out.println("Error");
}
}
}
public void start(){
if (t == null)
{
t = new Thread (this, "Start");
t.start ();
}
}
I have a program that estimates the value of PI every million trials. However, I want the program to be paused when I click on pause and to resumes when I click on run, using wait() and notify().
I must use multiple threads as well as a Boolean as a signal of where should it pause and run, but I do not know how. I am confused.
Any ideas?
package com.company;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Ex03 extends JFrame implements Runnable, ActionListener {
int n = 0;
int c = 0;
double Pi;
int change = 1000000;
boolean runing = true;
JLabel actualpi = new JLabel("The Actual value of PI " + Math.PI);
JLabel estimation = new JLabel("Current Estimate: ");
JLabel tri = new JLabel("Number Of Trials: " + n);
JButton run = new JButton("Run");
JButton pause = new JButton("Pause");
public Ex03() {
super("Ex 03");
setLayout(new GridLayout(4, 1));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 400);
setVisible(true);
add(actualpi);
add(estimation);
add(tri);
add(run);
run.addActionListener(this);
pause.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
Thread thread = new Thread(this);
if (e.getSource() == run) {
thread.start();
remove(run);
add(pause);
} else if (e.getSource() == pause) {
remove(pause);
add(run);
try {
thread.wait();
} catch (InterruptedException e1) {
}
}
}
public void run() {
n++;
while (runing) {
double x = Math.random();
double y = Math.random();
if (((x * x) + (y * y)) <= 1)
c++;
n++;
Pi = (4.0 * (double) c / n);
if (n == change) {
estimation.setText("Current Estimate: " + Pi);
tri.setText("Number Of Trials: " + n);
change = change + 1000000;
}
try {
Thread.sleep(0);
} catch (InterruptedException e) {
}
}
}
public static void main(String[] args) {
new Ex03();
}
}
Here is example how to do it in console application using Semaphore:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
public class Main {
public static void main(String[] args) throws Exception {
PiThread piThread = new PiThread();
piThread.start();
BufferedReader bufferRead = new BufferedReader(new InputStreamReader(System.in));
String cmd;
while ((cmd = bufferRead.readLine()) != null) {
System.out.println("write p to pause, r to resume, s to stop");
switch (cmd) {
case "p":
piThread.pauseComputation();
break;
case "r":
piThread.resumeComputation();
break;
case "s":
piThread.stopComputation();
piThread.join();
return;
}
}
}
public static class PiThread extends Thread {
private volatile boolean stop = false;
private volatile int total = 0;
private volatile int insideCircle = 0;
private Semaphore semaphore = new Semaphore(1, true);
#Override
public void run() {
while (!stop) {
for (int i = 0; i < 1000; i++) {
double x = Math.random();
double y = Math.random();
if (((x * x) + (y * y)) <= 1)
insideCircle++;
total++;
}
// using semaphores is slow
try {
// not to garbage stdout
Thread.sleep(100);
semaphore.acquire();
semaphore.release();
}
catch (InterruptedException e) {
// exit
return;
}
System.out.println("pi: " + getPiApproximation());
System.out.flush();
}
}
public void pauseComputation() {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void resumeComputation() {
semaphore.release();
}
public void stopComputation() {
stop = true;
}
public double getPiApproximation() {
return 4*(double)insideCircle / (double)total;
}
}
}
It may not be the best way to handle this in GUI but will give you a good start. The main idea is to use Semaphore to block worker thread. For this to work you must always call pauseComputation before resumeComputation otherwise there will be deadlock. After you call stopComputation you cannot resumeComputation or pauseComputation.
I want to display in my JPanel a JLabel with timer in this mode, for example:
03:50 sec
03:49 sec
....
....
00:00 sec
So I have build this code:
#SuppressWarnings("serial")
class TimeRefreshRace extends JLabel implements Runnable {
private boolean isAlive = false;
public void start() {
Thread t = new Thread(this);
isAlive = true;
t.start();
}
public void run() {
int timeInSecond = 185
int minutes = timeInSecond/60;
while (isAlive) {
try {
//TODO
} catch (InterruptedException e) {
log.logStackTrace(e);
}
}
}
}//fine autoclass
And with this code, I can start the JLabel
TimeRefreshRace arLabel = new TimeRefreshRace ();
arLabel.start();
So I have the time in secondo for example 180 second, how can I create the timer?
Here is an example, how to build a countdown label. You can use this pattern to create your component.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.WindowConstants;
public class TimerTest {
public static void main(String[] args) {
final JFrame frm = new JFrame("Countdown");
final JLabel countdownLabel = new JLabel("03:00");
final Timer t = new Timer(1000, new ActionListener() {
int time = 180;
#Override
public void actionPerformed(ActionEvent e) {
time--;
countdownLabel.setText(format(time / 60) + ":" + format(time % 60));
if (time == 0) {
final Timer timer = (Timer) e.getSource();
timer.stop();
}
}
});
frm.add(countdownLabel);
t.start();
frm.pack();
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setVisible(true);
}
private static String format(int i) {
String result = String.valueOf(i);
if (result.length() == 1) {
result = "0" + result;
}
return result;
}
}
You could within your try block call the Event Dispatcher Thread (EDT) and update your UI:
try {
SwingUtils.invokeLater(new Runnable() {
#Override
public void run() {
this.setText(minutes + " left");
}
}
//You could optionally block your thread to update your label every second.
}
Optionally, you could use a Timer instead of an actual thread, so your TimerRefreshRace will have its own timer which periodically fires an event. You would then use the same code within your try-catch block to update the UI.
I'm trying to learn how to properly use multi-threading and for some reason my code keeps freezing after one iteration through updating my progressbar. I've got the progressbar setup correctly because I've tested that on the side. I thought I had my multi-threading correct but the two classes dont seem to be communicating right. Can anyone with a trained eye spot my error here? Thank you
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.border.Border;
public class ProgressBar {
static int j = 0;
static int n = 0;
synchronized public static void main(String args[]) {
double percent = .01;
n = Integer.parseInt(JOptionPane.showInputDialog("pick a really big number for no reason"));
//this block is just the progress bar
JFrame f = new JFrame("Progress Bar");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container content = f.getContentPane();
JProgressBar progressBar = new JProgressBar();
progressBar.setValue(0);
progressBar.setStringPainted(true);
Border border = BorderFactory.createTitledBorder("Reading...");
progressBar.setBorder(border);
content.add(progressBar, BorderLayout.NORTH);
f.setSize(300, 100);
f.setVisible(true);
//this block is just the progress bar
Computation c = new Computation();
c.start();
while(percent <= 1.0){
if( j >= (n*percent) ){
progressBar.setValue((int) (percent*100));
progressBar.repaint();
percent += .01;
}
else{
continue;
}
}
}
public static class Computation extends Thread{
synchronized public void run(){
while( j < n ){
j++;
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
You need to synchronize the access to the shared data. The synchronization need to be done using the same object. Here is one solution, maybe not the best but at least it works. Also note the loop surrounding the wait. This is typical, to check whether you have met the condition to carry on.
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.border.Border;
import java.awt.*;
import java.util.concurrent.locks.Condition;
public class ProgressBar {
static final Object lock = new Object();
static int j = 0;
static int n = 0;
public static void main(String args[]) throws InterruptedException {
double percent = .01;
n = Integer.parseInt(JOptionPane.showInputDialog("pick a really big number for no reason"));
//this block is just the progress bar
JFrame f = new JFrame("Progress Bar");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container content = f.getContentPane();
JProgressBar progressBar = new JProgressBar();
progressBar.setValue(0);
progressBar.setStringPainted(true);
Border border = BorderFactory.createTitledBorder("Reading...");
progressBar.setBorder(border);
content.add(progressBar, BorderLayout.NORTH);
f.setSize(300, 100);
f.setVisible(true);
//this block is just the progress bar
Computation c = new Computation();
c.start();
while (percent <= 1.0) {
synchronized (lock) {
while (j < n * percent) {
lock.wait();
}
}
progressBar.setValue((int) (percent * 100));
progressBar.repaint();
percent += .01;
}
}
public static class Computation extends Thread {
public void run(){
while(true) {
synchronized (lock) {
if (j >= n) break;
j++;
lock.notify();
}
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
I have JList using DefaultListModel to update the strings in list in UI , returned by a class as shown
class ResponseGiver implements Callable<Future>{
int i;
//Constructor to initialize i
String call(){
...............
...............
return i;
}
and i have other class that will update the results obtained from above
class Viewer {
ExecutorService es = new Executors.newFixedThreadPool(10);
List<Future<String>> futures = new ArrayList<Future<String>>();
for(int i =0;i<10;i++)
{
futures.add(new ResponseGiver(i));
}
for(Future<String> x : futures) //loop 2nd will be called 10 times
{
String p = x.get();
//update GUI with p
}
Now the question is, suppose in loop 2nd , in the 5th loop, the get() function takes some time say 10 seconds, and during the mean time, the other futures from 6th to 10th have their result ready.
So my screen would wait for 5th result, even 6th to 10th are ready.
I want my screen to be updated as soon as any of the 10 futures return the result.
Using the standard API, you can use a ExecutorCompletionService. It allows submitting Callable instances and returns Future objects, just like a normal ExecutorService. But it additionally allows obtaining the Future objects in the order in which they are finished: Using the ExecutorCompletionService#take() method. This method blocks until a new Future is available. You can imagine this as the Futures being placed into a blocking queue.
You can start a thread that consumes these Future objects from the completion service. The result of such a Future may then be used to update the GUI. (Note that this update, in turn, has to be done on the Event Dispatch Thread again, using SwingUtilities.invokeLater).
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class ExecutorCompletionServiceTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new BorderLayout());
JButton button = new JButton("Run");
f.getContentPane().add(button, BorderLayout.NORTH);
final DefaultListModel<String> listModel = new DefaultListModel<String>();
JList<String> list = new JList<String>(listModel);
f.getContentPane().add(new JScrollPane(list), BorderLayout.CENTER);
final Callback callback = new Callback()
{
#Override
public void call(final String result)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
listModel.addElement(result);
}
});
}
};
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
createTasks(callback);
}
});
f.setSize(300, 300);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
interface Callback
{
void call(String result);
}
private static Random random = new Random(0);
static class ResponseGiver implements Callable<String>
{
private int i;
ResponseGiver(int i)
{
this.i = i;
}
#Override
public String call()
{
int delayMS = 250 + random.nextInt(500);
// Simulate a longer delay for task 5
if (i == 5)
{
delayMS += 3000;
}
try
{
System.out.println("For "+i+" waiting "+delayMS+" ms");
Thread.sleep(delayMS);
System.out.println("For "+i+" waiting "+delayMS+" ms DONE");
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
return String.valueOf(i);
}
}
private static void createTasks(final Callback callback)
{
ExecutorService executorService = Executors.newFixedThreadPool(10);
final CompletionService<String> executorCompletionService =
new ExecutorCompletionService<String>(executorService);
final int n = 10;
for (int i = 0; i < 10; i++)
{
executorCompletionService.submit(new ResponseGiver(i));
}
Thread thread = new Thread(new Runnable()
{
#Override
public void run()
{
processResults(executorCompletionService, n, callback);
}
});
thread.start();
}
private static void processResults(
CompletionService<String> completionService, int n, Callback callback)
{
for (int i = 0; i < n; i++)
{
try
{
Future<String> future = completionService.take();
String result = future.get();
if (result != null)
{
callback.call(result);
}
System.out.println("Processed "+(i+1)+" of "+n+" results");
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
catch (ExecutionException e)
{
e.printStackTrace();
}
}
}
}
Just use ListenableFuture from guava. It's much more convenient.