How to create a threaded console progress bar in Java? - java

I am trying to create a working progress bar program in Java so it can support both console and GUI applications.
The idea is use the thread to provide the current progress information, but it seems the thread code is not working well. Concurrency is so new to me.
I want it to advance the bar every time it is stepped up by one rather than completing the loop prematurely before the progress bar catches up. I guess the problem is timing?
[=====> ] 10% 1
2
3
4
5
6
7
8
9
10
[==================================================] 100%
Can someone tell me what I have gone wrong?
Main code
package console;
import java.util.ArrayList;
import console.ProgressThread;
public class ConsoleProgressBar
{
private static final long REFRESH_DELAY = 50;
private ProgressValue progress;
private ProgressThread target;
private Thread thread;
protected static class ProgressValue
{
protected long total = 0;
protected long current = 0;
protected ProgressValue(long n)
{
total = n;
}
protected synchronized void setMaxTotal(long n)
{
total = n;
}
protected synchronized void stepBy(long n)
{
current = current + n;
if (current > total) total = current;
}
protected synchronized void stepTo(long n)
{
current = n;
if (current > total) total = current;
}
protected synchronized long getCurrent()
{
return current;
}
protected synchronized long getTotal()
{
return total;
}
}
public ConsoleProgressBar(long totalItem)
{
this(totalItem, REFRESH_DELAY);
}
public ConsoleProgressBar(long totalItem, long refreshDelay)
{
progress = new ProgressValue(totalItem);
target = new ProgressThread(progress, refreshDelay);
}
public void start()
{
thread = new Thread(target);
thread.start();
}
public void stepBy(long n)
{
progress.stepBy(n);
}
public void stepTo(long n)
{
progress.stepTo(n);
}
public void step()
{
progress.stepBy(1);
}
public void setMaxTotal(long n)
{
progress.setMaxTotal(n);
}
public void stop()
{
target.terminate();
try
{
thread.join();
}
catch (InterruptedException ex)
{
}
}
public long getCurrent()
{
return progress.getCurrent();
}
public long getTotal()
{
return progress.getTotal();
}
public static void main(String[] args)
{
ArrayList<Integer> test = new ArrayList<>();
ConsoleProgressBar bar = new ConsoleProgressBar(10, 50);
bar.start();
for (int i = 0; i < 10; i++)
{
int sum = i + 5;
test.add(sum);
bar.step();
System.out.format("%s%n", bar.getCurrent());
}
bar.stop();
}
}
Thread code
package console;
import console.ConsoleProgressBar.ProgressValue;
public class ProgressThread implements Runnable
{
private static final int WIDTH = 50;
private volatile boolean terminated;
private ProgressValue progressRef;
private long timeMS;
public ProgressThread(ProgressValue ref, long refreshDelay)
{
progressRef = ref;
timeMS = refreshDelay;
terminated = false;
}
private void refreshProgressBar()
{
StringBuilder sb = new StringBuilder("\r[");
int percent = (int) Math.floor(100.0 * progressRef.current / progressRef.total);
for (int i = 0; i < WIDTH; i++)
{
if (i < (percent / 2)) sb.append("=");
else if (i == (percent / 2)) sb.append(">");
else sb.append(" ");
}
sb.append("] %s ");
if (percent >= 100) sb.append("%n");
System.out.printf(sb.toString(), percent + "%");
}
void terminate()
{
terminated = true;
}
public void run()
{
try
{
while (terminated == false)
{
refreshProgressBar();
Thread.sleep(timeMS);
}
refreshProgressBar();
}
catch (InterruptedException exc)
{
}
}
}

Why do you need a multithreaded application when it is just one task you are trying to achieve?
Nonetheless, to achieve what you want I suggest moving your execution entirely into either the thread class or into the main class.
If the main application is going to run something else, then ideally you'd put the execution in the thread class. However here I've put the execution into the main class. It could also just as easily go in the thread class.
As an example, I've edited run() in ProgressThread to just be this,
public void run()
{
while( terminated )
{
}
}
And I edited main in ConsoleProgressBar to this,
public static void main(String[] args)
{
ArrayList<Integer> test = new ArrayList<>();
ConsoleProgressBar bar = new ConsoleProgressBar(10, 50);
bar.start();
for (int i = 0; i <= 10; i++)
{
int sum = i + 5;
test.add(sum);
bar.refreshProgressBar();
System.out.format( "%s", bar.getCurrent() );
bar.step();
bar.sleep( 1000 );
}
bar.stop();
}
Note that I added the methods sleep( int n ) and refreshProgressBar() to bar so I can call the thread methods, similar to what you did with bar.start() and bar.stop().
To be clear, in ProgressThread I changed refreshProgressBar to public just for the sake of the example and added the following,
void sleep( int n )
{
try
{
Thread.sleep( n );
}
catch( InterruptedException ie )
{
ie.printStackTrace();
}
}
and the following to ConsoleProgressBar,
private void sleep( int n )
{
target.sleep( n );
}
private void refreshProgressBar()
{
target.refreshProgressBar();
}
The output (each line printing at one second intervals) is,
[> ] 0% 0
[=====> ] 10% 1
[==========> ] 20% 2
[===============> ] 30% 3
[====================> ] 40% 4
[=========================> ] 50% 5
[==============================> ] 60% 6
[===================================> ] 70% 7
[========================================> ] 80% 8
[=============================================> ] 90% 9
[==================================================] 100% 10
Not sure if this is what you are looking for but I suggest putting the execution into one place.

Related

How to synchronize shared variable with two Semaphores?

I have a exercise where I have a Feast where Person from persons N = 10 eat 1 amount of servings from pot at a time. Pot have maximum amount of servings M = 5. There is also a Cook who fill the pot when it is empty servingsAvailable = 0. Person can't eat during filling. I have to synchronize the threads only chaning the methods fill and getServings from Pot class (these methods were empty at the beginning).
Can you tell me what am I doing wrong in this code? Total amount should be 1000 but it is always less. I achieve situation where pot is filling then 5 persons eat, then its filling etc. but the number of servings eaten is inconsistent.
Person class
public class Person extends Thread { // Reprezentuje tubylca
Pot pot;
int servingsConsumed = 0;
public Person(String name, Pot pot) {
super(name);
this.pot = pot;
}
#Override
public void run() {
try {
for (int i = 0; i < 100; ++i) {
pot.getServing(this.getName());
++servingsConsumed;
Thread.yield();
}
} catch(InterruptedException e) {
return ;
}
}
}
Cook class
public class Cook extends Thread { // Reprezentuje kucharza
Pot pot;
public Cook(Pot pot) {
this.pot = pot;
setDaemon(true);
}
#Override
public void run() {
try {
while(!isInterrupted()) {
pot.fill();
}
} catch(InterruptedException e) {
return ;
}
}
}
Pot.class
import java.util.concurrent.Semaphore;
public class Pot {
static final int M = 5; // Pojemność kotła
private Semaphore emptyPot = new Semaphore(1);
private Semaphore available = new Semaphore(0);
private int servingsAvailable = 0;
private int totalServedCount = 0;
private synchronized void insertServings(int value) {
servingsAvailable = value;
}
private synchronized int removeServing() {
--servingsAvailable;
++totalServedCount;
return servingsAvailable;
}
public int getTotalServedCount() {
return totalServedCount;
}
public void getServing(String nameOfPerson) throws InterruptedException {
available.acquire();
if (servingsAvailable != 0) {
removeServing();
System.out.println(nameOfPerson + " ate 1 portion from pot");
}
available.release();
}
public void fill() throws InterruptedException {
available.acquire();
if (servingsAvailable == 0) {
insertServings(M);
System.out.println("Fill the pot with M = " + M);
}
available.release();
}
}
Feast class (main)
public class Feast {
public static void main(String[] args) throws InterruptedException {
Pot pot = new Pot();
Cook cook = new Cook(pot);
final int N = 10;
Person[] people = new Person[N];
for (int i = 0; i < people.length; ++i) {
people[i] = new Person("Person " + i, pot);
}
cook.start();
for (Thread t : people) {
t.start();
}
for (Thread t : people) {
t.join();
}
cook.interrupt();
System.out.printf("Total served: %d.\n", pot.getTotalServedCount());
for (Person p : people) {
System.out.printf("[%s] Ate %d servings.\n", p.getName(), p.servingsConsumed);
}
System.out.println("Finishing simulation.");
}
}
And the result I achieve so far: I think it should show 1000 instead of 245 here.
You're using your semaphores like a simple mutex, without any way for callers to know how many servings are available. If you want to signal the state of the pot, you should be updating them as the servings get filled and consumed:
public void getServing(String nameOfPerson) throws InterruptedException {
// take a permit and keep it
available.acquire();
System.out.println(nameOfPerson + " ate 1 portion from pot");
if (removeServing() == 0) {
// release a refill permit to the Cook
emptyPot.release();
}
}
public void fill() throws InterruptedException {
// wait till pot is empty
emptyPot.acquire();
insertServings(M);
System.out.println("Fill the pot with M = " + M);
// release a permit for each serving
available.release(M);
}

Sequential thread execution using wait/notify

Now I'm struggling with the task from the title. I create X threads, each of them prints Y equal digits (getting from constructor, for example "11111", "222222" etc) for Z times in cycle. So the result looks like:
111111111
222222222
333333333
111111111
222222222
333333333
for X = 3, Y = 9 and Z = 2.
Firstly I've solved this issue using sleep, interrupt and passing "next" thread to the constructor of previous one. One interrupts another etc. Next step is to get the same output using wait/notify instead sleep and interrupt. As far as I can see, it's neccesary to create the shared monitor object, to invoke wait after every printing and in a some moment " I should invoke notifyAll.
Current code is:
public class PrinterController {
private static final int THREADS_NUMBER = 5;
public static void main(String[] args) {
Printer[] printers = new Printer[THREADS_NUMBER];
for (int i = 0; i < THREADS_NUMBER; i++) {
printers[i] = new Printer(i);
printers[i].start();
}
}
}
public class Printer extends Thread {
private static int portion = 10;
private static int totalNumber = 100;
private int digit;
private static final Object monitor = new Object();
public Printer(int digit) {
this.digit = digit;
}
#Override
public void run() {
synchronized (monitor) {
int portionsNumber = totalNumber / portion;
for (int i = 0; i < portionsNumber; i++) {
printLine();
try {
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private void printLine() {
for (int j = 0; j < portion; j++) {
System.out.print(digit);
}
System.out.println();
}
}
Could you help to improve it? I found similar tasks but they don't contain appropriate answers. Thanks.
Final solution based on the Nadir's answer:
public class Printer extends Thread {
private static int portion = 10;
private static int totalNumber = 100;
private int digit;
static Object monitor = new Object();
static Integer counter = 0;
public Printer(int digit) {
this.digit = digit;
}
#Override
public void run() {
int portionsNumber = totalNumber / portion;
for (int i = 0; i < portionsNumber; i++) {
synchronized (monitor) {
while (digit != counter) {
try {
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
printLine();
monitor.notifyAll();
}
}
}
private void printLine() {
for (int j = 0; j < portion; j++) {
System.out.print(digit);
}
System.out.println();
counter = (counter + 1) % PrinterController.THREADS_NUMBER;
}
}
It can be accomplished with a class used to synchronize the threads (and even make sure they are orderer). All threads would share the same instance.
public class Synchronizer
{
private int nextThread;
private int maxNumThreads;
public Synchronizer(int numThreads)
{
maxNumThreads = numThreads;
nextThread = 0;
}
public void doSync(int threadId) throws Exception
{
synchronized(this)
{
while(nextThread != threadId)
{
wait();
}
}
}
public void threadDone(int threadId) throws Exception
{
synchronized(this)
{
nextThread = (threadId + 1) % maxNumThreads;
notifyAll();
}
}
}
On your thread's run(), you would call doSync() before printing anything. Then you would put the code for printing, and afterwards, you would call threadDone(), allowing the next thread to be released. The id is used to enforce an order.

Thread safe read/write to a counter

Im trying to make 2 threads that read/write to a counter using thread safe methods.
I have written some code to try test this but the read thread just reads the counter at its max (1000)
Main:
public static void main(String[] args) {
Counter c = new Counter();
Thread inc = new Increment(c);
Thread read = new Read(c);
inc.start();
read.start();
}
Counter:
public class Counter {
private int count;
public Counter() {
count = 0;
}
public synchronized void increment() {
count++;
}
public synchronized int getVal() {
return count;
}
}
Increment:
public class Increment extends Thread {
private static final int MAX = 1000;
private Counter myCounter;
public Increment(Counter c) {
myCounter = c;
}
public void run() {
for (int i = 0; i < MAX; i++) {
myCounter.increment();
}
}
}
Read:
public class Read extends Thread {
private static final int MAX = 1000;
private Counter myCounter;
public Read(Counter c) {
myCounter = c;
}
public void run() {
for (int i = 0; i < MAX; i++) {
System.out.println(myCounter.getVal());
}
}
}
Would I be better off using Atomic Integer to hold the value of the counter to allow me to safely increment it and get the value?
Your code is perfectly fine as is. It just so happened that your increment thread finished all its increments before the read thread got a chance to read. 1,000 increments takes almost no time at all.
If you want interleave execution of Read thread and Increment thread much more often then the natural operating system thread pre-emption, just make each thread give up their lock (by calling <lockedObject>.wait() followed by <lockedObject>.notify() or notifyAll() in the respective run() methods:
[In Reader]:
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (myCounter) {
System.out.println(myCounter.getVal());
try {
myCounter.wait(0L, 1);
myCounter.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
[In Increment]:
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (myCounter) {
myCounter.increment();
try {
myCounter.wait(0L, 1);
myCounter.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Upping the MAX constant to 1_000_000_000 (1 billion) made the treads interleave as well every now and then (on my machine interleave happened just by gazing at few printouts between 150 and 400_000 iterations).

Java Threads with ConcurrentModificationException

I'm currently working on my first multithreaded software - a program, which calculates prime numbers...
Basically I create n (number of Threads) runnables. These runnables are added to an ArrayList. They check, whether a number is a prime. If the number is a prime I add it into an long array for later use. Since I want the primes to be in correct order in this array I need specific Threads to wait for others. I do this by looping through the ArrayList (see above) and wait for the threads, which check a lower number.
After a thread is done I want to remove it from the given ArrayList, but I cant since the other threads are still looping through it (This is the reason why the ConcurrentModificationException occurs I guess - This is my first time working with threads...).
I honestly hope that any of you guys can help me :)
Thank your really much!
Matthias
My runnable class (I just create four objects of this class in the main method):
import java.util.ArrayList;
public class PrimeRunnable implements Runnable {
//Static Util
public static ArrayList<PrimeRunnable> runningThreads = new ArrayList<PrimeRunnable>();
public static long[] primes;
public static int nextFreeIndex = 1;
public static long nextPossiblePrime = 3;
//Object specific
private long numberToCheck;
private Thread primeThread;
private String threadName;
private long threadID;
public PrimeRunnable() {
numberToCheck = nextPossiblePrime;
increaseNextPossiblePrime();
threadName = "ThreadToCheck" + numberToCheck;
threadID = numberToCheck;
runningThreads.add(this);
}
#Override
public void run() {
boolean isPrime = true;
double sqrtOfPossiblePrime = Math.sqrt(numberToCheck);
long lastDevider = 0;
for(int index = 0; index < nextFreeIndex; index++) {
lastDevider = primes[index];
if(numberToCheck%primes[index] == 0) {
isPrime = false;
break;
}
if(primes[index] > sqrtOfPossiblePrime) {
break;
}
}
while(lastDevider < sqrtOfPossiblePrime) {
lastDevider += 1;
if(numberToCheck%lastDevider == 0) {
isPrime = false;
break;
}
}
if(isPrime) {
//Wait for lower Threads.
for(PrimeRunnable runnable : runningThreads) {
if(runnable.getThreadID() < this.getThreadID()) {
try {
runnable.primeThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
primes[nextFreeIndex] = numberToCheck;
increaseNextFreeIndex();
System.out.println(numberToCheck);
}
runningThreads.remove(this);
}
public void start() {
if(primeThread == null) {
primeThread = new Thread(this, threadName);
}
primeThread.start();
}
public void reset() {
numberToCheck = nextPossiblePrime;
increaseNextPossiblePrime();
threadName = "ThreadToCheck" + numberToCheck;
threadID = numberToCheck;
//No need to readd into runningThread, since we only manipulate an already existing object.
primeThread = new Thread(this, threadName);
primeThread.start();
}
public static void setUpperBorder(int upperBorder) {
if(primes == null) {
primes = new long[upperBorder];
primes[0] = 2;
} else {
System.err.println("You are not allowed to set the upper border while running.");
}
}
public long getNumberToCheck() {
return numberToCheck;
}
private void increaseNextPossiblePrime() {
nextPossiblePrime += 2;
}
private void increaseNextFreeIndex() {
nextFreeIndex += 2;
}
public long getThreadID() {
return threadID;
}
public boolean isAlive() {
return primeThread.isAlive();
}
}
I was able to replicate the issue and fix it using Java implementation of a concurrent list CopyOnWriteArrayList
Here's my main class
public class PrimeRunnableMain {
public static void main(String[] args) {
PrimeRunnable.setUpperBorder(10);
PrimeRunnable primeRunnable1 = new PrimeRunnable();
PrimeRunnable primeRunnable2 = new PrimeRunnable();
PrimeRunnable primeRunnable3 = new PrimeRunnable();
PrimeRunnable primeRunnable4 = new PrimeRunnable();
primeRunnable1.start();
primeRunnable2.start();
primeRunnable3.start();
primeRunnable4.start();
}
}
and here's PrimeRunnable
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class PrimeRunnable implements Runnable {
// Static Util
public static List<PrimeRunnable> runningThreads = new CopyOnWriteArrayList<PrimeRunnable>();
public static long[] primes;
public static int nextFreeIndex = 1;
public static long nextPossiblePrime = 3;
// Object specific
private long numberToCheck;
private Thread primeThread;
private String threadName;
private long threadID;
public PrimeRunnable() {
numberToCheck = nextPossiblePrime;
increaseNextPossiblePrime();
threadName = "ThreadToCheck" + numberToCheck;
threadID = numberToCheck;
runningThreads.add(this);
}
#Override
public void run() {
boolean isPrime = true;
double sqrtOfPossiblePrime = Math.sqrt(numberToCheck);
long lastDevider = 0;
for (int index = 0; index < nextFreeIndex; index++) {
lastDevider = primes[index];
if (numberToCheck % primes[index] == 0) {
isPrime = false;
break;
}
if (primes[index] > sqrtOfPossiblePrime) {
break;
}
}
while (lastDevider < sqrtOfPossiblePrime) {
lastDevider += 1;
if (numberToCheck % lastDevider == 0) {
isPrime = false;
break;
}
}
if (isPrime) {
// Wait for lower Threads.
for (PrimeRunnable runnable : runningThreads) {
if (runnable.getThreadID() < this.getThreadID()) {
try {
runnable.primeThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
primes[nextFreeIndex] = numberToCheck;
increaseNextFreeIndex();
System.out.println(numberToCheck);
}
runningThreads.remove(this);
}
public void start() {
if (primeThread == null) {
primeThread = new Thread(this, threadName);
}
primeThread.start();
}
public void reset() {
numberToCheck = nextPossiblePrime;
increaseNextPossiblePrime();
threadName = "ThreadToCheck" + numberToCheck;
threadID = numberToCheck;
// No need to readd into runningThread, since we only manipulate an
// already existing object.
primeThread = new Thread(this, threadName);
primeThread.start();
}
public static void setUpperBorder(int upperBorder) {
if (primes == null) {
primes = new long[upperBorder];
primes[0] = 2;
} else {
System.err
.println("You are not allowed to set the upper border while running.");
}
}
public long getNumberToCheck() {
return numberToCheck;
}
private void increaseNextPossiblePrime() {
nextPossiblePrime += 2;
}
private void increaseNextFreeIndex() {
nextFreeIndex += 2;
}
public long getThreadID() {
return threadID;
}
public boolean isAlive() {
return primeThread.isAlive();
}
}
What about a PrimeListener class that contains a synchronized method publishPrime that inserts the prime in the correct position in the list? Inserting at the right position into the list should not take too much time, if you start at the last index of a LinkedList.
Alternatively you could also insert it into a SortedSet (implementation: TreeSet). I presume you don't want any duplicate primes anyway. In that case synchronizedSortedSet may be directly used instead of the listener.
Note that you still seem rather stuck on lower level structures. When programming concurrently on Java it pays off to use the higher level constructs (executors, futures, concurrent queue's etc. etc.).
The main distinction between fail-fast and fail-safe iterators is
whether or not the collection can be modified while it is being
iterated. Fail-safe iterators allow this; fail-fast iterators do not.
Fail-fast iterators operate directly on the collection itself. During
iteration, fail-fast iterators fail as soon as they realize that the
collection has been modified (i.e., upon realizing that a member has
been added, modified, or removed) and will throw a
ConcurrentModificationException. Some examples include ArrayList,
HashSet, and HashMap (most JDK1.4 collections are implemented to be
fail-fast). Fail-safe iterates operate on a cloned copy of the
collection and therefore do not throw an exception if the collection
is modified during iteration. Examples would include iterators
returned by ConcurrentHashMap or CopyOnWriteArrayList.

Multithreading doesn't work. What is incorrect?

It's a little program written with a purpose of studying multithreading. I expected to get in main method different random numbers after run. About 4 numbers per second. But I got many thousands of zeros. Where is an error?
Main Class:
public class Main {
public static void main(String[] args) {
ExternalWorld externalWorld = new ExternalWorld();
externalWorld.start();
int x = 0;
while (true) {
while(!externalWorld.signal){
System.out.println("qqq");}
System.out.println(++x + ") " + externalWorld.getAnInt());
}
}
}
ExternalWorld Class:
import java.util.Random;
public class ExternalWorld extends Thread {
private int anInt = 0;
public boolean signal = false;
#Override
public void run() {
Random random = new Random(100);
while(true) {
anInt = random.nextInt(100);
signal = true;
try {
Thread.sleep(200);
signal = false;
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public int getAnInt() {
if (!signal) {
int p = 1 / 0;
}
int result = anInt;
anInt = 0;
return result;
}
}
problem:
private int anInt = 0;
public boolean signal = false;
You are access those variables from one thread to another thus giving you 0 and false on the main thread
solution:
use volatile keyword to access those variables from multiple threads
sample:
private volatile int anInt = 0;
public volatile boolean signal = false;

Categories

Resources