I have a Runnable "NanoClock" class which keeps updating a private volatile double value in its run() method.
This class also has a getTime() method which returns the double value. Another class ("Master") is constructing the NanoClock class and creates a thread, as well as calling the start() method.
After it did this it calls the getTime() method several times (with a delay), but the value is not updating. What am I doing wrong?
NanoClock.java :
public class NanoClock implements Runnable {
private volatile boolean running;
private volatile double time;
public NanoClock() {
time = System.currentTimeMillis();
}
#Override
public void run() {
running = true;
while(running) {
try {
if(System.currentTimeMillis() > time) {
time = System.currentTimeMillis();
}
//This returns the updated value continuously when commented out
//System.out.println("Time: " + String.format("%.6f", unix_time));
Thread.sleep(2000);
} catch(Exception exc) {
exc.printStackTrace();
System.exit(1);
}
}
}
public double getTime() {
return time;
}
public void end() {
running = false;
}
}
Master.java:
public class Master {
public static void main(String[] args) {
try {
NanoClock nClock = new NanoClock();
Thread clockThread = new Thread(new NanoClock());
clockThread.setPriority(10);
clockThread.start();
//MY_ISSUE: This returns the same value every time
for(int a = 0; a < 10; a++) {
System.out.println("Time: " + nClock.getTime());
}
//MY_ISSUE: This cannot stop the while loop - I tested it with
//the println in the NanoClock class.
nClock.end();
System.out.println("Done!");
catch(Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
You've got two instances of NanoClock: one of them is an anonymous new NanoClock() which, as the Runnable in your other thread is happily keeping time in the backgound; the other is nClock, which is sitting idly by in the foreground in your main thread.
nClock should have been the Runnable in that other thread:
Thread clockThread = new Thread(nClock); // not new NanoClock()
This may not be the entire solution, but it should be a big step in the right direction.
System.currentTimeMillis() returns a long, but you store it in a double, which causes a loss of precision. When you change the member time (and also the return type of its getter) to a long you should get the expected result.
As a rule of thumb: When working with time units long is most appropriate datatype most of the time. Floating point numbers are not suitable to store precise results.
Thread.sleep(2000);
System.out.println("Time: " + nClock.getTime());
the for in main() must be sleep(2000)
If the code below will take 2 seconds, then the time will change.
//MY_ISSUE: This returns the same value every time
for(int a = 0; a < 10; a++) {
System.out.println("Time: " + nClock.getTime());
}
However a for loop with 10 iterations and a system.out will not even take a millisecond so it will not change.
Why 2 seconds? because you have a Thread.sleep in your runnable code.
Thread.sleep(2000);
Which means, the next update will be in 2 seconds.
And use System.nanoTime() instead of System.currentTimeMillis() since you really wanted nano time not millis.
Updated:
In my machine
public static void main(String args[]) {
long start = System.currentTimeMillis();
for(int a = 0; a < 10; a++) {
System.out.println("Iterating " + a);
}
long end = System.currentTimeMillis();
System.out.println("Start = " + start);
System.out.println("End = " + end);
}
Result, there is no difference in the start time and end time
Iterating 0
Iterating 1
Iterating 2
Iterating 3
Iterating 4
Iterating 5
Iterating 6
Iterating 7
Iterating 8
Iterating 9
Start = 1499592836298
End = 1499592836298
That code block executed so fast that it did not take even a single millisecond. Depending on the timing, it may take 1 millisecond.
Changing it to System.nanoTime()
public static void main(String args[]) {
long start = System.nanoTime();
for(int a = 0; a < 10; a++) {
System.out.println("Iterating " + a);
}
long end = System.nanoTime();
System.out.println("Start = " + start);
System.out.println("End = " + end);
}
Result, there is a difference in the start time and end time.
Iterating 0
Iterating 1
Iterating 2
Iterating 3
Iterating 4
Iterating 5
Iterating 6
Iterating 7
Iterating 8
Iterating 9
Start = 1012518090518837
End = 1012518091012960
Related
I have a piece of the source code in java8:
public class Test {
public static void main(String[] args) {
testObject(1.3);
testObject(1.4);
}
private static void testObject(double num) {
System.out.println("test:" + num);
long sta = System.currentTimeMillis();
int size = 10000000;
Object[] o = new Object[(int) (size * num)];
for (int i = 0; i < size; i++) {
o[i] = "" + i;
}
System.out.println("object[]: " + (System.currentTimeMillis() - sta) + " ms");
}
}
execution Result:
test:1.3
object[]: 7694 ms
test:1.4
object[]: 3826 ms
Why is the running time so different when my quantity is 1.4 * size?
I wanted to see how Java array assignment works, but I couldn't find anything on google.
In addition you have to keep in mind that System.currentTimeMillis returns a "Wall-Clock-Time". If your OS does a reschedule during the for-loop and a different process gets the cpu, the Wall-Clock-Time increases but your program won't execute.
I am working on Thread for the first time and I tried to code an example I saw on the internet. An ArrayList of numbers must be divided into 4 parts, and 4 separate threads need to find the odd and even numbers in those parts and add them to the "evens" or "odds" list. Although I do not have any problems with the algorithm, I have problems with Threads.
Since the codes are not very long, I am adding them completely.
My Runnable Class:
package ThreadRace;
public class OddEvenFinder implements Runnable {
private final int id;
private final int size;
public OddEvenFinder(int id, int size) {
this.id = id;
this.size = size;
}
#Override
public void run() {
int start = id * this.size;
int end = start + this.size;
while (start < end) {
if (Starter.numbers.get(start) % 2 == 0) {
Starter.evens.add(start);
}
else {
Starter.odds.add(start);
}
start++;
}
}
}
My testing class:
package ThreadRace;
import java.util.ArrayList;
import java.util.List;
public class Starter {
public static List<Integer> numbers = new ArrayList<>();
public static List<Integer> evens = new ArrayList<>();
public static List<Integer> odds = new ArrayList<>();
public static void main(String[] args) throws InterruptedException {
for (int i = 1; i <= 10000; i++) {
numbers.add(i);
}
OddEvenFinder f1 = new OddEvenFinder(0, numbers.size() / 4);
OddEvenFinder f2 = new OddEvenFinder(1, numbers.size() / 4);
OddEvenFinder f3 = new OddEvenFinder(2, numbers.size() / 4);
OddEvenFinder f4 = new OddEvenFinder(3, numbers.size() / 4);
Thread thread1 = new Thread(f1);
Thread thread2 = new Thread(f2);
Thread thread3 = new Thread(f3);
Thread thread4 = new Thread(f4);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread1.join();
thread2.join();
thread3.join();
thread4.join();
System.out.println(evens.size());
System.out.println(odds.size());
}
}
When I run the application this way, the length of the evens and odds lists should be 5000-5000, but I get a result between 3000-4000.
Shouldn't the .join() function wait for threads to finish? How can there be numbers that are not included in the lists?
The interesting part is that the problem is almost resolved when I add a few words to debug.
When I edit the code like this:
#Override
public void run() {
int start = id * this.size;
int end = start + this.size;
while (start < end) {
System.out.println("Thread number " + (this.id + 1) + " is working");
if (Starter.numbers.get(start) % 2 == 0) {
System.out.println(start + " added to evens");
Starter.evens.add(start);
}
else {
System.out.println(start + " added to odds");
Starter.odds.add(start);
}
start++;
}
}
The output I get gives almost accurate results like 4999-5000. When I set the size of the numbers array to a smaller value such as 4000-5000, it gives the correct result.
I have 2 questions:
1- Why .join() is not working or what am I wrong about .join()?
2- How is it that printing a few texts makes the program run more accurately?
In the JavaDocs of ArrayList, it says in bold "Note that this implementation is not synchronised". So if several threads want to add an element at the same time, only the last call of the method will set the real value. The values of the other threads are simply overwritten. Therefore, you will get fewer numbers than expected.
In order for the list to be filled in a synchronised way, you should use the keyword "synchronized" as shown below.
synchronized (Starter.evens) {
Starter.evens.add(start);
}
and
synchronized (Starter.odds) {
Starter.odds.add(start);
}
This TestCode is supposed to create an stream of numbers in seconds.
Collect 10 samples, and average the time which each samples comes out.
I did try to use if-else, but the variable from if doesn't share with else.
Please correct me if I'm wrong.
I don't understand lambda just yet.
public class TestCode {
private int eachTwoSec;
// supposed to aList.add 10 items
// average the time needed in between each aList.add (2 obviously)
public void avgTimeTaken() {
ArrayList aList = new ArrayList();
for (int i = 0; i < 10; i++) {
aList.add(eachTwoSec);
}
}
// return a number every two seconds (endless stream of samples)
// samples 50,52,54,56,58,60,2,4,6,8,10
public void twoSecTime() {
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(Dummies.class.getName()).log(Level.SEVERE, null, ex);
}
LocalDateTime ldt = LocalDateTime.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("ss");
eachTwoSec = Integer.parseInt(ldt.format(dtf));
System.out.println(eachTwoSec);
twoSecTime();
}
public TestCode() {
// construct
avgTimeTaken();
new Thread(this::twoSecTime).start();
}
public static void main(String[] args) {
// just a start point
new TestCode();
}
}
The literal answer to the question "How do I average the contents in ArrayList?" for a List<Integer> is:
list.stream().mapToInt(Integer::intValue).average();
Though I suspect that's not really what you need to know given the concurrency issues in your code.
This may help to do what you want (or give you a place from which to proceed).
I use a timer to take action every 2000 ms. I prefer using the Swing timer and not messing around with TimerTasks.
I don't just add 2 sec but grab the current nanoSecond time
This introduces latency errors introduced by various parts of the code and
of synchronicities.
I add the microseconds to the ArrayList. These are in the form of delta from the most recent to the previously recorded value.
and when count == 10 I stop the timer and invoke the averaging method.
Most of the work is done on the EDT (normally a bad thing but okay for this exercise). If that were a problem, another thread could be started to handle the load.
I then use the original main thread to signal wait to leave the JVM. Imo, preferred over System.exit(0);
The gathered data and final average are all in microseconds.
import java.util.ArrayList;
import javax.swing.Timer;
public class TestCode {
Timer timer;
int delay = 2000; // milliseconds
int count = 0;
long last;
ArrayList<Integer> aList = new ArrayList<>();
Object mainThread;
public void avgTimeTaken() {
double sum = 0;
for (Integer secs : aList) {
sum += secs;
}
System.out.println("Avg = " + sum / aList.size());
}
public void twoSecTime() {
long now = System.nanoTime();
int delta = (int) (now / 1000 - last / 1000); // microseconds
last = now;
aList.add(delta);
System.out.println(delta);
count++;
if (count == 10) {
// stop the time
timer.stop();
// get the averages
avgTimeTaken();
// wake up the wait to exit the JVM
// twoSecTime is run on the EDT via timer
// so need to use mainThread
synchronized (mainThread) {
mainThread.notifyAll();
}
}
}
public static void main(String[] args) {
new TestCode().start();
}
public void start() {
mainThread = this;
timer = new Timer(2000, (ae) -> twoSecTime());
last = System.nanoTime(); // initialize last
timer.start();
synchronized (this) {
try {
wait(); // main thread waiting until all is done
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
}
Though there are similar issues, I couldn't found any similar examples like the one I got. I really appreciate any help understanding where I got wrong with my implementation.
What I'm trying to do:
I have a Main class Driver, which can instantiates unknown number of threads. Each thread call a singleton class which should simulate a 'fake' file transfer action.
The issue I have is that I need to limit the concurrent transfers to 2 transfers, regardless the number of concurrent requests.
The way I tried to solve my problem is by adding each new Thread in a ConcurrentLinkedQueue and managing it by using Executors.newFixedThreadPool(POOL_SIZE) to limit the concurrent threads to be 2. for every interation - I poll new thread from the pool using pool.submit.
The Problem I have is my output is like this:
[Thread1], [Thread1, Thread2], [Thread1, Thread2, Thread3]...
While it should be:
[Thread1, Thread2], [Thread3, Thread4]
Why the limitation doesn't work here?
My implementation:
Copier - this is my singleton class.
public class Copier {
private final int POOL_SIZE = 2;
private static volatile Copier instance = null;
private Queue<Reportable> threadQuere = new ConcurrentLinkedQueue();
private static FileCopier fileCopier = new FileCopier();
private Copier() {
}
public static Copier getInstance() {
if (instance == null) {
synchronized (Copier.class) {
if (instance == null) {
instance = new Copier();
}
}
}
return instance;
}
public void fileTransfer(Reportable reportable) {
threadQuere.add(reportable);
ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
for (int i=0; i < threadQuere.size(); i++) {
System.out.println("This is the " + (i+1) + " thread");
pool.submit(new CopyThread());
}
pool.shutdown();
try {
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
CopyThread - represend a thread class
public class CopyThread implements Reportable, Runnable {
private static FileCopier fileCopier = new FileCopier();
#Override
public void report(String bitrate) {
System.out.println(bitrate);
}
#Override
public void run() {
synchronized(fileCopier) {
long startTime = System.nanoTime();
long bytes = fileCopier.copyFile();
long endTime = System.nanoTime();
double duration = (double)(endTime - startTime) / 1000000000; // get in seconds
double bytesInMegas = (double) bytes / 1000000;
report(bytesInMegas + "MB were transferred in " + duration + " seconds");
}
}
}
Driver - my main class where do I create all the threads
public class Driver {
public static void main(String[] args) {
Copier copier = Copier.getInstance();
CopyThread copyThread1 = new CopyThread();
CopyThread copyThread2 = new CopyThread();
CopyThread copyThread3 = new CopyThread();
CopyThread copyThread4 = new CopyThread();
copier.fileTransfer(copyThread1);
copier.fileTransfer(copyThread2);
copier.fileTransfer(copyThread3);
copier.fileTransfer(copyThread4);
int q = 0;
}
}
A simpler solution would be a Semaphore with 2 permits.
This makes sure that "outside" threads can't bypass the limit either, since your solution expects that the simultaneous tasks are limited by the size of the threadpool.
Your solution uses several concurrency tools when a single one would suffice. Your DCL singleton is a bit outdated too.
Everything is probably fine here (although a bit weird). You are printing the thread numbers before submiting, what you need to do is put print in a run method, and you will see that everything works fine. The print are all gonna go off normally, because the area where you are using print has nothing to do with Executors. There is more problems with your code, but I think you did all that just for testing/learning so that's why it's like that.
In that case, like I said, put prints in the run method (you can use some static variable in CopyThread class for counting threads). Your output will be something like 2 prints about thread numbers (1 and 2), 2 prints about how long transfer took and then prints about thread 3 and 4 (I say probably, because we are working with threads, can't be sure of anything) - all this at the step 4 ofcourse, when your fileTransfer submits 4 runnables. Your singleton is outdated, because it uses double checked locking, which is wrong on multithreaded machine, check this: here. That's not ruining your program so worry about it later. About everything else (weird queue usage, fileTransfer method making new threads pools etc.) like I said, it's probably for learning, but if it's not - your queue may as well be deleted, you are using it only for counting and counting like this could be done with some counter variable, and your fileTransfer method should just submit new runnable to pool (which would be instance variable) to transfer a file, not create pool and submit few runnables, it's kinda anty-intuitive.
Edit: check this, I put all in Cat.java for simplicity, changed some things that I had to change (I don't have FileCopier class etc., but answer to your problem is here):
import java.util.*;
import java.util.concurrent.*;
class Copier {
private final int POOL_SIZE = 2;
private static volatile Copier instance = null;
private Copier() {
}
public static Copier getInstance() {
if (instance == null) {
synchronized (Copier.class) {
if (instance == null) {
instance = new Copier();
}
}
}
return instance;
}
public void fileTransfer() {
ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
for (int i=0; i < 4; i++) {
pool.submit(new CopyThread());
}
pool.shutdown();
try {
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class CopyThread implements Runnable {
private static int counter = 0;
public void report(String bitrate) {
System.out.println(bitrate);
}
Object obj = new Object();
#Override
public void run() {
synchronized(obj) {
System.out.println("This is the " + (++counter) + " thread");
long startTime = System.nanoTime();
long bytes = 0;
for(int i=0; i<100000; i++)
bytes+=1;
long endTime = System.nanoTime();
double duration = (double)(endTime - startTime) / 1000000000; // get in seconds
double bytesInMegas = (double) bytes / 1000000;
report(bytesInMegas + "MB were transferred in " + duration + " seconds");
}
}
}
public class Cat {
public static void main(String[] args) {
Copier copier = Copier.getInstance();
copier.fileTransfer();
}
}
So, I ran a test and the results make no sense to me. Lets consider the following code:
ThreadStuffCounter counter_1 = new ThreadStuffCounter(1);
while(counter_1.doProceed) {
Thread.sleep(500);
Thread thread = new Thread(counter_1);
thread.start();
}
With the Runnable as follows:
package test;
public class ThreadStuffCounter implements Runnable {
public volatile boolean doProceed = true;
private int id = -1;
public volatile int i = -1;
public ThreadStuffCounter(int id) {
this.id = id;
}
#Override
public void run() {
for (i = 0; i < 10; i++) {
System.out.println("i = " + i + " in runnable id = " + id);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
doProceed = false;
}
}
Only one instance of counter is shared between threads. It takes less time for another thread to start then even one increment to be made on the counter.doProceed should, as I understand never be set to false and the loop should continue indefinitely until I get an out of memory exception and cannot start any more threads.
How is it possible for the loop to exit?
EDIT: Modified code to make sure the answer below is correct.
package test;
public class ThreadStuffCounter implements Runnable{
public volatile boolean doProceed = true;
private int id = -1;
volatile int i = -1;
public ThreadStuffCounter(int id){
this.id = id;
}
#Override
public void run() {
i = 0;
while (i < 10){
System.out.println("i = " + i + " in runnable id = " + id +
"; from thead id = " + Thread.currentThread().getId());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
ThreadStuff.doProceed = false;
}
}
And
package test;
public class ThreadStuff {
public static volatile boolean doProceed = true;
public static void main (String[] args) throws InterruptedException{
ThreadStuffCounter counter_1 = new ThreadStuffCounter(1);
while(doProceed){
Thread.sleep(500);
Thread thread = new Thread(counter_1);
thread.start();
}
}
}
Also, it appears more then n threads are needed if you are running for i < n. You need however many, so that n threads increment at the same time.
When at least one of the threads executes the for loop and i value is greater or equal than 10, then doProceed variable will be false (yes, this may happen), and since it's volatile this will stop the execution of the while loop that creates and starts new threads. Then, is up to all the threads to just finish executing the code of the for loop and then finishing their execution. This seems to happen because the time to start a new thread in your environment is slower than the time for a current thread to finish its execution. Also, note that several threads may increase i value, which will accelerate the for loop execution.
Probably if you loop to a higher value (not tested) then this could generate an infinite loop and the application will break when there aren't enough resources to create and start new threads.
After some tests using the limit as 10, 50 and 1000. I noticed that when you have a bigger value, since lots of threads are created, all of them increase the value of i at the same time and i slowly starts to get closer to the limit value set in the for loop. Description of my current environment:
OS: Windows 7 Professional 64 bits
Processor: Intel(R) Core(TM) i5-2520M CPU # 2.50GHz (4 CPUs), ~2.5GHz
Ram: 8192MB