Accessing variables in threads? - java

I'm a beginner in java, and I just started using threads yesterday. I'm having a problem accessing variables in a thread, which I want to display.
Long story short, I made a (shitty) clock loop, that runs when the program starts. After certain actions, I have a method that checks the time, but I don't know how to access the variables in the thread to make this possible.
This is my main method:
public static void main(String[] args) {
Thread timeRunning = new Thread(new Clock());
Clock clock = new Clock();
Commands command = new Commands();
timeRunning.start();
command.whatsTheTime();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
command.whatsTheTime();
This is my clock loop:
public class Clock implements Runnable{
public void run(){
//Time
int seconds = 0;
int minutes = 0;
int hours = 0;
//"Clock" loop
while(hours < 24) {
while (minutes < 59) {
while (seconds < 59) {
seconds++;
try {
Thread.sleep(30);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
if(seconds == 59) {
minutes++;
seconds = 0;
}
if(minutes == 59) {
hours++;
minutes = 0;
}
}
}
}
}
This is the "whatsTheTime()" method:
public void whatsTheTime() {
System.out.println("The time is: " + clock.hours + ":" + clock.minutes + ":" + clock.seconds);
}
But it doesn't work. What I want to know is, how can I access the seconds, minutes and hours from the run() in the Clock class.
I'm sorry if this is a very basic question, but I don't know how to access it. I tried googling the solution, but can't seem to find it. I might be seraching for the wrong thing, but as I said, I'm only a few months into java, so searching for the solution is one of the things I need to get better at aswell.

Related

How do I average the contents in ArrayList?

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();
}
}
}
}

Java: Volatile variable not updating (get and set methods not working)

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

Rate-limit calls to an IRC bot

I am working on a IRC bot that has the command !Scouter and it will generate a random number.... I already have that done, what I wanted to make was a cool down system to keep from people spamming it over and over again.
here is my code.
public class Twitchbot extends PircBot {
Random dice = new Random();
int number;
for(int counter=1; counter<=1;counter++) {
number = 1+dice.nextInt(9001);
System.out.println(number + " ");
}
public Twitchbot() {
this.setName("Blah");
}
public void onMessage(String channel, String sender, String login, String hostname, String message) {
if (message.equalsIgnoreCase("!Scouter")) {
sendMessage(channel,": The time is now " + sender + number);
for(int counter=1; counter<=1;counter++) {
number = 1+dice.nextInt(9001);
System.out.println(number + " ");
try {
Thread.sleep(5000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
}
I tried using this code for a cool down
try {
Thread.sleep(5000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
but all it did is do the code after 5 seconds of sleeping. I don't want the command !Scouter to register during that cool down. is there a better way of doing it?
You could save the current system-time on a successfull call using:
lastCall = System.currentTimeMillis();
and before, you check
if(System.currentTimeMillis() - lastCall >= DELAY)
where DELAY is a time in milliseconds (1 second equals 1000 milliseconds).
if that statement is true, set lastCall to the current time:
lastCall = System.currentTimeMillis();
and call the normal code.
It would look something like this:
long lastCall = 0L; //Initializing
public void onMessage(String channel, String sender,
String login, String hostname, String message) {
if (message.equalsIgnoreCase("!Scouter")) {
if(System.currentTimeMillis() - lastCall >= 5000)
{
lastCall = System.currentTimeMillis(); // Set lastCall again
sendMessage(channel,": The time is now " + sender + number);
for(int counter=1; counter<=1;counter++) {
number = 1+dice.nextInt(9001);
System.out.println(number + " ");
}
}
}
}
The problem is that onMessage is called asynchronously, so you cannot prevent it from being called with a sleep.
The easiest workaround is to store the current time as an instance variable, and return immediately in onMessage if the difference between the stored time and the current time is less than 5 seconds.
I don't fully understand the functionality of your system, but I see that your system gets stuck everytime it enters on Sleep.
If you want to get rid of this behavior, a good approach would be to use a Thread as an anonymous class call, and do the things in background.
I would do it like this:
if (message.equalsIgnoreCase("!Scouter")) {
sendMessage(channel,": The time is now " + sender + number);
new Thread() {
#Override
public void run() {
for(int counter=1; counter<=1;counter++) {
number = 1+dice.nextInt(9001);
System.out.println(number + " ");
try {
sleep(5000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}.run();
}
Hope it helps.

Thread works when else statement is present, but when it's absent, thread stops working

It's my first time using threads in java and I came across with weird problem.
public class ServerSender implements Runnable {
DatagramSocket udpSocket;
DatagramPacket sendPacket;
long currentTime = 0;
long elapsed = 0;
public ServerSender(DatagramSocket udpSocket) {
this.udpSocket = udpSocket;
System.out.println("Sender live!");
}
public void sendToClient(byte[] bytes) throws IOException {
sendPacket = new DatagramPacket(bytes, bytes.length, Server.clientIp, Server.clientPort);
udpSocket.send(sendPacket);
}
#Override
public void run() {
while(true)
{
if(Server.isGameLive)
{
currentTime = System.nanoTime();
if(elapsed / 1000000 >= 100) // send snapshot every 100ms
{
synchronized(Server.snapshot)
{
try
{
sendToClient(Server.snapshot.toByteArray());
}
catch (IOException e)
{
e.printStackTrace();
}
}
elapsed = 0;
System.out.println("Sending snapshot to client...");
} else {
System.out.println("not elapsed");
}
elapsed += System.nanoTime() - currentTime;
System.out.println(elapsed / 1000000);
} else {
System.out.println("not live");
}
}
}
}
This code works how it should but when I remove else statements from run method it's not working...
#Override
public void run() {
while(true)
{
if(Server.isGameLive)
{
currentTime = System.nanoTime();
if(elapsed / 1000000 >= 100) // send snapshot every 100ms
{
synchronized(Server.snapshot)
{
try
{
sendToClient(Server.snapshot.toByteArray());
}
catch (IOException e)
{
e.printStackTrace();
}
}
elapsed = 0;
System.out.println("Sending snapshot to client...");
}
elapsed += System.nanoTime() - currentTime;
System.out.println(elapsed / 1000000);
}
}
}
Can someone explain what's wrong there?
My completely wild guess is that you are reading non-volatile values which you are changed in another thread.
When you read a non-volatile field, the JIT is free to inline the value and thus it might never see the value you changed it to.
However, if you slow down the loop, e.g. by writing to the console, it might not run enough times to be JITted so you don't see this optimisation and the loop stops as expected.
http://vanillajava.blogspot.com/2012/01/demonstrating-when-volatile-is-required.html
First, make sure Server.isGameLive is volatile, so you're not running into memory visibility issues.
The piece of code you're measuring could take less time to run than the resolution of System.nanoTime() with this code.
Your time calculation should rather be something like:
public void run() {
currentTime = System.nanoTime();
while(true) {
if(Server.isGameLive) {
if(elapsed / 1000000 >= 100) {
synchronized(Server.snapshot) {
try {
sendToClient(Server.snapshot.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
}
elapsed = 0;
currentTime = System.nanoTime();
System.out.println("Sending snapshot to client...");
}
elapsed = System.nanoTime() - currentTime;
System.out.println(elapsed / 1000000);
}
}
}
I think that removed println was slowing the operation a little down, so you can add a Thread.sleep(1); at the end of the loop.
This way not only you prevent this problem but also will allow other threads to use the CPU.

How to create a count-up effect for a textView in Android

I am working on an app that counts the number of questions marks in a few paragraphs of text.
After the scanning is done (which takes no time at all) I would love to have the total presented after the number goes from 0 to TOTAL. So, for 10: 0,1,2,3,4,5,6,7,8,9 10 and then STOP.
I have tried a couple of different techniques:
TextView sentScore = (TextView) findViewById(R.id.sentScore);
long freezeTime = SystemClock.uptimeMillis();
for (int i = 0; i < sent; i++) {
if ((SystemClock.uptimeMillis() - freezeTime) > 500) {
sentScore.setText(sent.toString());
}
}
Also I tried this:
for (int i = 0; i < sent; i++) {
// try {
Thread.sleep(500);
} catch (InterruptedException ie) {
sentScore.setText(i.toString());
}
}
I am sure these are both completely amateur attempts. Any help would be much-appreciated.
Thanks,
Richard
I've used a more conventional Android-style animation for this:
ValueAnimator animator = new ValueAnimator();
animator.setObjectValues(0, count);
animator.addUpdateListener(new AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
view.setText(String.valueOf(animation.getAnimatedValue()));
}
});
animator.setEvaluator(new TypeEvaluator<Integer>() {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
return Math.round(startValue + (endValue - startValue) * fraction);
}
});
animator.setDuration(1000);
animator.start();
You can play with the 0 and count values to make the counter go from any number to any number, and play with the 1000 to set the duration of the entire animation.
Note that this supports Android API level 11 and above, but you can use the awesome nineoldandroids project to make it backward compatible easily.
Try this:
private int counter = 0;
private int total = 30; // the total number
//...
//when you want to start the counting start the thread bellow.
new Thread(new Runnable() {
public void run() {
while (counter < total) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.post(new Runnable() {
public void run() {
t.setText("" + counter);
}
});
counter++;
}
}
}).start();
The question is very old, but I am posting this so that it would help someone else.
I have used these 2 amazing libraries.
Try them
https://github.com/MasayukiSuda/CountAnimationTextView
Or
2. https://github.com/robinhood/ticker
Hope this helps :) Happy Coding!!!
Use TextSitcher
for the best effects. It will transform the text softly.
When coming to the change of the text use the below Code.
> int number = 0;
> Timer obj = new Timer();
> TimerTask tt = new TimerTask() {
> #Override public void run() {
> // TODO Auto-generated method stub
> textView.setText(number++);
> if(number < score)
> obj.schedule(tt, 200); } };
> obj.schedule(tt, 200);
Use a worker thread to do the waiting and update your UI thread.
You could use an AsyncTask, though it might be an overkill for this job. If you use this, In the doInBackground() loop over the number of sleep periods and after every sleep period, update the count in the UIthread.
There you go! Slukain just gave you the working code :P
Maybe try changing the for loop to something like:
int count = 0;
while (count != sent) {
if ((SystemClock.uptimeMillis() - freezeTime) > 500) {
count++;
sentScore.setText("" + count);
freezeTime = SystemClock.uptimeMillis();
}
}

Categories