I'm trying to use threads to show a progress bar on the CLI in java while doing a long operation (generating md5sums for a batch of large files).
I've written a bit of code, and it works, but I'd like to know if I'm using threads correctly as I'm pretty new to this.
I have two class files, ProgressThreadTest.java and CountToABillion.java
CountToABillion.java:
public class CountToABillion implements Runnable {
double count = 0;
public void echoCount() {
System.out.println(count);
}
#Override
public void run() {
for (double x=0;x<1000000000;x++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
count = x;
echoCount();
}
}
}
ProgressThreadTest.java:
public class ProgressThreadTest {
public static void main(String[] args) throws InterruptedException {
Thread doCount=new Thread(new CountToABillion());
doCount.start();
}
}
It works as expected and counts upwards on the command line.
Anyone have any comments on whether or not this is a good way to do threads?
Also, because I am updating the progress in the counting loop, it will update every 10ms. How would I change the code to only output the count once every second?
Using javax.swing.Timer is probably the easier solution:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class CountToABillion implements Runnable {
double count = 0;
Timer progressTimer;
public void echoCount() {
System.out.println(count);
}
#Override
public void run() {
progressTimer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
echoCount();
}
});
progressTimer.setRepeats(true);
progressTimer.start();
for (double x=0;x<1000000000;x++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
count = x;
}
progressTimer.stop();
}
}
Using java.util.concurrent.ScheduledThreadPoolExecutor is the better and more scalable solution:
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class CountToABillion implements Runnable {
double count = 0;
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);
public void echoCount() {
System.out.println(count);
}
#Override
public void run() {
Runnable task = new Runnable() {
public void run() {
echoCount();
}
};
exec.scheduleAtFixedRate(task, 1, 1, TimeUnit.SECONDS);
for (double x=0;x<1000000000;x++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
count = x;
}
exec.shutdownNow();
}
}
Option 1:
int sleep = 10; //ms
int echo = 1000; //ms
for (double x=0;x<1000000000;x++) {
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
count = x;
if((x*sleep % echo) == 0) {
echoCount();
}
}
Option 2:
Create a new Class to manage your counter, it should be able to add, reset and so on. You will have to make sure it's thread safe (writing new values in case you want to update from various threads).
Make one thread that increases the counter in given intervals
Make another thread that polls the current count in other given intervals and print.
long last=0;
#Override
public void run() {
for (double x=0;x<1000000000;x++) {
try {
doWork();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
count = x;
if((System.currentTimeMillis()-last)>=1000) //post every second
{
last=System.currentTimeMillis();
echoCount();
}
}
}
This will print the count once every second assuming "work" does not take more than a second.
#Override
public void run() {
for (int i = 0; i < 1000000000; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
count = i;
if(i % 100 == 0) {
echoCount();
}
}
}
By using i % 100 == 0 you're checking if i is divisible by 100 without rest value. If that's the case, it means that you have ran 100 times 10ms which is 1000ms which is 1s. So you will output your echoCountt() every second.
This is an okay way to use threads. But your thread will keep running until it has counted to 10000000 seconds.
On a sidenote, you should use 'i' instead of 'x' in for loops. It's more widely used like this and will be easier to read for experienced java developers
Related
I am trying to stop the for loop and wait until the method has finished and continue once it has called onFinish. I was suggested to use either CyclicBarrier or syncronized wait/notify, but neither of them work.
When I run the method without the "stoppers", it always reaches to the onFinish, calling all 3 System.out.prints, but when I add either CyclicBarrier or syncronized it just does not start ticking. Meaning it only prints the first line countDownTimer first call and then stops and does nothing.
Just to make it shorter I have added both stoppers here to show how I did either of them, but I did use them seperately.
What can I do to make it "tick" ?
cyclicBarrier = new CyclicBarrier(2);
object = new Object();
for (int i = 0; i < sentenceList.size() - 1; i++) {
String currentLyricLine = sentenceList.get(i).content;
long diff = sentenceList.get(i+1).fromTime - sentenceList.get(i).fromTime;
int interval = (int) (diff / sentenceList.get(i).wordCount);
if(isFirstLine) {
startLyricCountDownTimer(diff, interval, currentLyricLine, coloredLyricsTextViewFirstLine);
isFirstLine = false;
} else {
startLyricCountDownTimer(diff, interval, currentLyricLine, coloredLyricsTextViewSecondLine);
isFirstLine = true;
}
//First tried with this
synchronized (object) {
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//Then tried with this
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
private void startLyricCountDownTimer(final long millisInFuture, final int countDownInterval, String lyrics, final ColoredLyricsTextView coloredLyricsText){
System.out.println("countDownTimer first call" );
coloredLyricsText.setText(lyrics);
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
new CountDownTimer(millisInFuture,10) {
#Override
public void onTick(long millisUntilFinished) {
System.out.println("countDownTimer second call + " + millisUntilFinished);
//Do some stuff (irrelevant since it never gets here)
}
#Override
public void onFinish() {
System.out.println("countDownTimer last call" );
//First tried with this
synchronized (object) {
object.notify();
}
//Then tried with this
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}.start();
}
});
}
If i understand correctly then it was also mentioned that I run my loop on UI thread which is why everything stops. And well I do not wish to stop the UI thread, just to wait for one countDownTimer to finish, then start a new loop.
#Override
public void run() {
act.runOnUiThread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < randomNumber.size(); i++) {
Log.d("N",randomNumber.get(i).toString());
if (randomNumber.get(i).intValue() == 1) imgColor.setBackgroundColor(Color.RED);
if (randomNumber.get(i).intValue() == 2) imgColor.setBackgroundColor(Color.GREEN);
if (randomNumber.get(i).intValue() == 3) imgColor.setBackgroundColor(Color.BLUE);
if (randomNumber.get(i).intValue() == 4) imgColor.setBackgroundColor(Color.YELLOW);
try {
Thread.sleep(1750);
} catch (Exception e) {
Thread.currentThread().interrupt();
}
imgColor.setBackgroundColor(Color.BLACK);
try {
Thread.sleep(400);
} catch (Exception e) {
Thread.currentThread().interrupt();
}
}
Toast.makeText(act, "Ripeti la sequenza", Toast.LENGTH_SHORT).show();
}
});
}
I have a number list, with numbers from 1 to 4. I want to picture the ImageView according to the numbers in the list, but I need a sequence of colors, so I need (for example) show the RED color, after wait 1,75 seconds, and after the GREEN and so on, but it doesn't work ! What should I do ?
For such tasks Thread isn't the best choice. I recommend you to use View.postDelayed method. So you should get something like that.
void setRandomColor(){
if(!hasRandomColor())
return;
imgColor.setBackgroundColor(getRandomColor());
imgColor.postDelayed(new Runnable(){
void run(){
setRandomColor();
}
}, 1750); // update color again after 1.75 sec
}
...
setRandomColor();
I have already seen this question : How pause and then resume a thread?
I have seen many questions in stackoverflow related to my issue, but I couldn't understand them because they are abstract and not specific enough to my sitiuation.
There are 2 Count Down Labels. When you click Start Button, the countdown is executed. In the same way, when you click Pause Button, it should be paused. However, I am getting an error: Exception in thread "AWT-EventQueue-0" java.lang.IllegalMonitorStateException
2 Threads are started, but I can't stop it with the wait() method. Please let me know how can I stop threads, and implement resume button. Thanks. Easy Example below
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
class FirstCountDown extends SwingWorker<Integer, Integer> {
public Integer doInBackground() {
for(int i=0; i<1000; i++){
CountDown.count1.setText(String.valueOf(1000-i));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
}
class SecondCountDown extends SwingWorker<Integer, Integer> {
public Integer doInBackground(){
for(int i=0; i<1000; i++){
CountDown.count2.setText(String.valueOf(1000-i));
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
}
class CountDown extends JFrame {
static JLabel count1;
static JLabel count2;
static JButton startButton;
static JButton pauseButton;
static JButton resumeButton;
FirstCountDown first = new FirstCountDown();
SecondCountDown second = new SecondCountDown();
public CountDown(){
count1 = new JLabel("1000");
count2 = new JLabel("1000");
startButton = new JButton("start");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
first.execute();
second.execute();
}
});
pauseButton = new JButton("pause");
pauseButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
try {
first.wait();
second.wait();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
resumeButton = new JButton("resume");
setSize(300,100);
setLayout(new FlowLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(count1);
add(count2);
add(startButton);
add(pauseButton);
add(resumeButton);
setVisible(true);
}
public static void main(String args[]) {
CountDown g = new CountDown();
}
}
You can't suspend a thread execution by invoking wait() on it. wait() suspend the current thread until another thread calls notify() or notifyAll() on the same object the previous thread called wait() on. Moreover, in order to call wait(), notify() or notifyAll() on an object, the calling thread must hold that object's monitor by doing
synchronized(object) {
object.wait();
}
In order to suspend your counting, you need a flag and provide two methods to suspend and resume your counting. Something like:
class FirstCountDown extends SwingWorker<Integer, Integer> {
private _suspended = false;
public synchronized void suspend() { _suspended = true; notify(); }
public synchronized void resume() { _suspended = false; notify(); }
public Integer doInBackground() {
for(int i=0; i<1000; i++) {
synchronized(this) {
while (_suspended) {
wait(); // The current thread will block until some else calls notify()
// Then if _suspended is false, it keeps looping the for
}
}
CountDown.count1.setText(String.valueOf(1000-i));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
}
In my android application I want an automatically refresh every 60 seconds. So I tried it like this:
public void refresh_check() {
Thread myThread = new Thread()
{
int counter = 0;
#Override
public void run() {
MyActivity.this.runOnUiThread(new Runnable(){
#Override
public void run() {
while (counter < 60) {
try {
Thread.sleep(1000);
counter += 1;
System.out.println("Counter: " + counter);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
refresh();
}});
super.run();
}
};
myThread.start();
}
This works in the way that it prints the counter into logcat but in my Application I get a black view. refresh() is just a function with a http request, and this works alone, so the mistake has to be in the thread at any place :/ Can someone help?
You are not utilizing the Thread correctly. Running long tasks on the UI thread is just like not using a Thread at all. To accomplish what you need you should do it like this:
public void refresh_check() {
Thread myThread = new Thread()
{
int counter = 0;
#Override
public void run() {
while (counter < 60) {
try {
Thread.sleep(1000);
counter += 1;
System.out.println("Counter: " + counter); //I think this may cause exception, if it does try removing it
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
refresh(); // In refresh(), use TextView.post(runnable) to post update the TextView from outside the UI thread or use handlers
}});
super.run();
};
myThread.start();
}
Also, take a look at AsyncTask class, it enables you to run long tasks outside UI thread (doInBackground()) as well as update UI with the result from (onPostExecute())
I am trying to print odd and even numbers using 2 different threads alternately. I was able to achieve it using wait, notify and synchronize block but now i want to evaluate if we can achieve it without using wait, notify and synchronize.
Following is the code i have but its not working:
public class OddEvenUsingAtomic {
AtomicInteger nm = new AtomicInteger(0);
AtomicBoolean chk = new AtomicBoolean(true);
public static void main(String args[]) {
final OddEvenUsingAtomic pc = new OddEvenUsingAtomic();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (pc.chk.compareAndSet(true, false)) {
System.out.println("Odd: " + pc.nm.incrementAndGet());
}
}
}
}).start();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (true) {
if (pc.chk.compareAndSet(false, true)) {
System.out.println("Even: " + pc.nm.incrementAndGet());
}
}
}
}).start();
}
}
Any ideas?
I created another version after suggestions from Bruno which seems to be working better:
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class OddEvenUsingAtomic {
AtomicInteger nm = new AtomicInteger(0);
AtomicBoolean chk = new AtomicBoolean(true);
public static void main(String args[]) {
final OddEvenUsingAtomic pc = new OddEvenUsingAtomic();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (pc.chk.get() == Boolean.TRUE) {
System.out.println("Odd: " + pc.nm.incrementAndGet());
pc.chk.compareAndSet(true, false);
}
}
}
}).start();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (true) {
if (pc.chk.get() == Boolean.FALSE) {
System.out.println("Even: " + pc.nm.incrementAndGet());
pc.chk.compareAndSet(false, true);
}
}
}
}).start();
}
}
The code is not correctly synchronized, that's the problem.
The following execution order is allowed in your code:
First thread sees chk == true, sets it to false and enters the if block.
Second thread sees chk == false, sets it to true and enters the if block.
Now, you have 2 threads both inside their if blocks, getting ready to:
incrementAndGet() the number
Print it.
Therefore, you have absolutely no control on what is going to happen.
You can have any of the threads call incrementAndGet(), therefore you can have thread "Odd" printing, first, an odd number, and later, an even number.
You can have the first thread print the number, loop, see that the condition is satisfied again (since the second thread has set chk to true again, print, all of this before the second thread had the chance to print).
As you can see, to achieve the result you want, you must have the following operations done atomically:
compareAndSet() the boolean
incrementAndGet() the number
print it
If the 3 operations are not atomic, then you can have the threads being scheduled to run the operations in any possible order, you have no control on the output. The easiest way to achieve this is to use a synchronized block:
public static void main(final String... args) {
final Object o = new Object();
// ... thread 1 ...
synchronized(o) {
if (boolean is in the expected state) { change boolean, get number, increment, print }
}
// ... thread 2 ...
synchronized(o) {
if (boolean is in the expected state) { change boolean, get number, increment, print }
}
}
Here are two threads printing odds and evens with no wait, notify, or synchronized (at least not in the code you can see):
import java.util.concurrent.*;
public class ThreadSignaling {
public static void main(String[] args) {
BlockingQueue<Integer> evens = new LinkedBlockingQueue<>();
BlockingQueue<Integer> odds = new LinkedBlockingQueue<>();
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(() -> takeAndOfferNext(evens, odds));
executorService.submit(() -> takeAndOfferNext(odds, evens));
evens.offer(0);
}
private static void takeAndOfferNext(BlockingQueue<Integer> takeFrom,
BlockingQueue<Integer> offerTo) {
while (true) {
try {
int i = takeFrom.take();
System.out.println(i);
offerTo.offer(i + 1);
} catch (InterruptedException e) {
throw new IllegalStateException("Unexpected interrupt", e);
}
}
}
}
class MultiThreading {
Integer counter = 0;
Thread even;
Thread odd;
boolean flagEven = true;
boolean flagOdd;
class ThreadEven implements Runnable {
#Override
public void run() {
try {
while (counter < 100) {
if (flagEven) {
System.out.println(counter);
counter++;
flagEven = false;
flagOdd = true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ThreadOdd implements Runnable {
#Override
public void run() {
try {
synchronized (even) {
while (counter < 100) {
if (flagOdd) {
System.out.println(counter);
counter++;
flagOdd = false;
flagEven = true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void start() {
even = new Thread(new ThreadEven());
odd = new Thread(new ThreadOdd());
even.start();
odd.start();
}
}
}
call in the main method
new MultiThreading().start();