Encapsulating the Thread Logic in Stopwatch (Part 2)

Courtesy: timeanddate.com

Welcome to the second part of this series “Powerful Design Patterns to create an Amazing Stopwatch App”. Until now, we have just figured out the working of our core stopwatch class. But the problem is that we have to explicitly call the getTime() method of our stopwatch class to get the time at a particular instant. But that was not satisfactory for us. We wanted to see the stopwatch running and that is the reason, from the client-side, we made a different thread just to watch the stopwatch running with continuous time-updates. But the client-side code is becoming heavier and it is not good to have the client do so many things just to use the stopwatch. We should always think about keeping the client-side code smaller and smaller. The real question now arises: Can we give the client the same functionality but with lesser code? What can we do more?

Previous Tutorial

If you are reading this part first, you should definitely check out Part 1 of this series to catch up.

What can we do about making the client-side code lesser and lesser in size? We could do one thing. We could encapsulate all the logic associated with the threads into our core Stopwatch class so that the users don’t even have to think about creating threads by themselves. The users will only hit the start() and stop() methods and will be able to see the stopwatch running right away, without even going into any kind of thread business.

Here’s what the logic will look like.

  • When the client of the stopwatch hits start(), a new thread will be created by the stopwatch itself and it will be started right away. This thread will continuously print the stopwatch time.
  • When the client hits stop(), that thread will get destroyed and will no longer print the time giving the user the confirmation that the stopwatch has been paused.

Seems pretty simple right? And it is simple. This tutorial will be a rather short one because next we are going to implement the Observer design pattern and I wanted to give it a separate tutorial. No more blabbering. Let’s get started.

This is what the Stopwatch.java class looks like now.

public class Stopwatch
{
private long offset, currentStart;
private boolean isStopped;

public Stopwatch()
{
offset = 0L;
currentStart = System.currentTimeMillis();
isStopped = true;
}

public void start()
{
if(isStopped)
{
currentStart = System.currentTimeMillis() - offset;
}

isStopped = false;
}

public void stop()
{
if(!isStopped)
{
offset = System.currentTimeMillis() - currentStart;
}
isStopped = true;
}

public long getTime()
{
if(!isStopped)
return System.currentTimeMillis() - currentStart;
else
return offset;
}
}

And our StopwatchTest.java looks like

public class StopwatchTest {
public static void main(String[] args) {
Stopwatch sw = new Stopwatch();

Thread observerThread = new Thread(new Runnable() {
@Override
public void run() {
while (true)
{
System.out.print("\rTime: "+ sw.getTime());
sleep(10);
}

}
});
observerThread.start();


System.out.println("\nStarting Stopwatch: ");
sw.start();
sleep(2000);
sw.stop();
System.out.println("\nStopwatch Stopped. ");

sleep(2000);

System.out.println("\nStarting Stopwatch: ");
sw.start();
sleep(2000);
sw.stop();
System.out.println("\nStopwatch Stopped. ");

}

public static void sleep(int time)
{
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

This thread creation from the client-side is the thing that is bothering us right now. We have to take the logic that is inside the run() method of the Runnable, that is passed to the thread, and put it inside the stopwatch class.

The first thing that we are going to do is to make the Stopwatch class implement the Runnable interface.

public class Stopwatch implements Runnable
{
....
}

Next, we are going to override the run() method that the Runnable interface wants us to override and copy the printing logic inside it.

public class Stopwatch implements Runnable
{
...

@Override
public void run() {
while(true)
{
System.out.print("\rTime: "+ getTime());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

Notice we are using the getTime() method. Since Thread.sleep() throws an InterruptedException, we surrounded it with a try-catch block. One problem still persists. There is no stopping logic that stops the thread from printing the time. The print method is in an infinite loop. Earlier we had no choice but to run an infinite loop. But now we have a variable that can help us here. Remember “isStopped”? Time to use it now. We will stop printing the time when the stopwatch gets stopped. The loop condition now becomes:

public void run() {
while(!isStopped)
{
System.out.print("\rTime: "+ getTime());
...
}
}

Next, we will create a class variable that stores the current thread of execution.

public class Stopwatch implements Runnable
{
private long offset, currentStart;
private boolean isStopped;
private Thread th; // Thread that prints the time of the stopwatch
...
}

Now when the client calls the start() method, we just need to create a new thread and start it.

public void start()
{
if(isStopped)
{
th = new Thread(this);
th.start();
currentStart = System.currentTimeMillis() - offset;
}

isStopped = false;
}

When the client calls the stop() method, we need to destroy the thread. Since Java does not give us anything to destroy a thread, we are just going to dereference the thread variable by making it “null” and rely on the Garbage collector to clean it up.

public void stop()
{
if(!isStopped)
{
th =null;
offset = System.currentTimeMillis() - currentStart;
}
isStopped = true;
}

Note: The thread will stop printing as soon as the client hits the stop() method as the “isStopped” boolean becomes true which makes the thread’s while loop condition false, completing the thread execution.

And that’s all we got to do with the Stopwatch class. Time to clean up the client-side code and enjoy the encapsulation.

Let’s head over to StopwatchTest.java.

Stopwatch sw = new Stopwatch();

// Thread observerThread = new Thread(new Runnable() {
// @Override
// public void run() {
// while (true)
// {
// System.out.print("\rTime: "+ sw.getTime());
// sleep(10);
// }
//
// }
// });
// observerThread.start();


System.out.println("\nStarting Stopwatch: ");
sw.start();
sleep(2000);
sw.stop();
System.out.println("\nStopwatch Stopped. ");

sleep(2000);

System.out.println("\nStarting Stopwatch: ");
sw.start();
sleep(2000);
sw.stop();
System.out.println("\nStopwatch Stopped. ");

}

The only thing that needs to be deleted is the part that is commented. Once you delete this, you will find the client-side code cleaner.

Let’s test this out.

Works just as before but this time the client doesn’t have to think about creating threads, passing it a runnable, and all that bullsh*t.

Just identified one problem with this whole thing. Look at what we are doing. We are just printing the time when the stopwatch is running (on a different thread). In most practical applications, printing the time is not what is required. The thing that is required is to send the time asynchronously from the stopwatch to the client-side and the client can figure out what to do with the time. Luckily there is one Design Pattern that can help us out here and you have heard it many times: Observer. In the next blog, we are going to take a look at what this pattern is and how we can modify our code to implement this pattern. Meet you in the next one.

Next Tutorial:

Applying the Observer Pattern

Full Code

The Full code is here.

Stopwatch.java

public class Stopwatch implements Runnable
{
private long offset, currentStart;
private boolean isStopped;
Thread th;

public Stopwatch()
{
offset = 0L;
currentStart = System.currentTimeMillis();
isStopped = true;
}

public void start()
{
if(isStopped)
{
th = new Thread(this);
th.start();
currentStart = System.currentTimeMillis() - offset;
}

isStopped = false;
}

public void stop()
{
if(!isStopped)
{
th =null;
offset = System.currentTimeMillis() - currentStart;
}
isStopped = true;
}

public long getTime()
{
if(!isStopped)
return System.currentTimeMillis() - currentStart;
else
return offset;
}

@Override
public void run() {
while(!isStopped)
{
System.out.print("\rTime: "+ getTime());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

StopwatchTest.java

public class StopwatchTest {
public static void main(String[] args) {
Stopwatch sw = new Stopwatch();



System.out.println("\nStarting Stopwatch: ");
sw.start();
sleep(2000);
sw.stop();
System.out.println("\nStopwatch Stopped. ");

sleep(2000);

System.out.println("\nStarting Stopwatch: ");
sw.start();
sleep(2000);
sw.stop();
System.out.println("\nStopwatch Stopped. ");

}

public static void sleep(int time)
{
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

References:


Encapsulating the Thread Logic in Stopwatch (Part 2) was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Rajtilak Pal

Courtesy: timeanddate.com

Welcome to the second part of this series “Powerful Design Patterns to create an Amazing Stopwatch App”. Until now, we have just figured out the working of our core stopwatch class. But the problem is that we have to explicitly call the getTime() method of our stopwatch class to get the time at a particular instant. But that was not satisfactory for us. We wanted to see the stopwatch running and that is the reason, from the client-side, we made a different thread just to watch the stopwatch running with continuous time-updates. But the client-side code is becoming heavier and it is not good to have the client do so many things just to use the stopwatch. We should always think about keeping the client-side code smaller and smaller. The real question now arises: Can we give the client the same functionality but with lesser code? What can we do more?

Previous Tutorial

If you are reading this part first, you should definitely check out Part 1 of this series to catch up.

What can we do about making the client-side code lesser and lesser in size? We could do one thing. We could encapsulate all the logic associated with the threads into our core Stopwatch class so that the users don't even have to think about creating threads by themselves. The users will only hit the start() and stop() methods and will be able to see the stopwatch running right away, without even going into any kind of thread business.

Here’s what the logic will look like.

  • When the client of the stopwatch hits start(), a new thread will be created by the stopwatch itself and it will be started right away. This thread will continuously print the stopwatch time.
  • When the client hits stop(), that thread will get destroyed and will no longer print the time giving the user the confirmation that the stopwatch has been paused.

Seems pretty simple right? And it is simple. This tutorial will be a rather short one because next we are going to implement the Observer design pattern and I wanted to give it a separate tutorial. No more blabbering. Let’s get started.

This is what the Stopwatch.java class looks like now.

public class Stopwatch
{
private long offset, currentStart;
private boolean isStopped;

public Stopwatch()
{
offset = 0L;
currentStart = System.currentTimeMillis();
isStopped = true;
}

public void start()
{
if(isStopped)
{
currentStart = System.currentTimeMillis() - offset;
}

isStopped = false;
}

public void stop()
{
if(!isStopped)
{
offset = System.currentTimeMillis() - currentStart;
}
isStopped = true;
}

public long getTime()
{
if(!isStopped)
return System.currentTimeMillis() - currentStart;
else
return offset;
}
}

And our StopwatchTest.java looks like

public class StopwatchTest {
public static void main(String[] args) {
Stopwatch sw = new Stopwatch();

Thread observerThread = new Thread(new Runnable() {
@Override
public void run() {
while (true)
{
System.out.print("\rTime: "+ sw.getTime());
sleep(10);
}

}
});
observerThread.start();


System.out.println("\nStarting Stopwatch: ");
sw.start();
sleep(2000);
sw.stop();
System.out.println("\nStopwatch Stopped. ");

sleep(2000);

System.out.println("\nStarting Stopwatch: ");
sw.start();
sleep(2000);
sw.stop();
System.out.println("\nStopwatch Stopped. ");

}

public static void sleep(int time)
{
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

This thread creation from the client-side is the thing that is bothering us right now. We have to take the logic that is inside the run() method of the Runnable, that is passed to the thread, and put it inside the stopwatch class.

The first thing that we are going to do is to make the Stopwatch class implement the Runnable interface.

public class Stopwatch implements Runnable
{
....
}

Next, we are going to override the run() method that the Runnable interface wants us to override and copy the printing logic inside it.

public class Stopwatch implements Runnable
{
...

@Override
public void run() {
while(true)
{
System.out.print("\rTime: "+ getTime());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

Notice we are using the getTime() method. Since Thread.sleep() throws an InterruptedException, we surrounded it with a try-catch block. One problem still persists. There is no stopping logic that stops the thread from printing the time. The print method is in an infinite loop. Earlier we had no choice but to run an infinite loop. But now we have a variable that can help us here. Remember “isStopped”? Time to use it now. We will stop printing the time when the stopwatch gets stopped. The loop condition now becomes:

public void run() {
while(!isStopped)
{
System.out.print("\rTime: "+ getTime());
...
}
}

Next, we will create a class variable that stores the current thread of execution.

public class Stopwatch implements Runnable
{
private long offset, currentStart;
private boolean isStopped;
private Thread th; // Thread that prints the time of the stopwatch
...
}

Now when the client calls the start() method, we just need to create a new thread and start it.

public void start()
{
if(isStopped)
{
th = new Thread(this);
th.start();
currentStart = System.currentTimeMillis() - offset;
}

isStopped = false;
}

When the client calls the stop() method, we need to destroy the thread. Since Java does not give us anything to destroy a thread, we are just going to dereference the thread variable by making it “null” and rely on the Garbage collector to clean it up.

public void stop()
{
if(!isStopped)
{
th =null;
offset = System.currentTimeMillis() - currentStart;
}
isStopped = true;
}

Note: The thread will stop printing as soon as the client hits the stop() method as the “isStopped” boolean becomes true which makes the thread’s while loop condition false, completing the thread execution.

And that’s all we got to do with the Stopwatch class. Time to clean up the client-side code and enjoy the encapsulation.

Let’s head over to StopwatchTest.java.

Stopwatch sw = new Stopwatch();

// Thread observerThread = new Thread(new Runnable() {
// @Override
// public void run() {
// while (true)
// {
// System.out.print("\rTime: "+ sw.getTime());
// sleep(10);
// }
//
// }
// });
// observerThread.start();


System.out.println("\nStarting Stopwatch: ");
sw.start();
sleep(2000);
sw.stop();
System.out.println("\nStopwatch Stopped. ");

sleep(2000);

System.out.println("\nStarting Stopwatch: ");
sw.start();
sleep(2000);
sw.stop();
System.out.println("\nStopwatch Stopped. ");

}

The only thing that needs to be deleted is the part that is commented. Once you delete this, you will find the client-side code cleaner.

Let’s test this out.

Works just as before but this time the client doesn’t have to think about creating threads, passing it a runnable, and all that bullsh*t.

Just identified one problem with this whole thing. Look at what we are doing. We are just printing the time when the stopwatch is running (on a different thread). In most practical applications, printing the time is not what is required. The thing that is required is to send the time asynchronously from the stopwatch to the client-side and the client can figure out what to do with the time. Luckily there is one Design Pattern that can help us out here and you have heard it many times: Observer. In the next blog, we are going to take a look at what this pattern is and how we can modify our code to implement this pattern. Meet you in the next one.

Next Tutorial:

Applying the Observer Pattern

Full Code

The Full code is here.

Stopwatch.java

public class Stopwatch implements Runnable
{
private long offset, currentStart;
private boolean isStopped;
Thread th;

public Stopwatch()
{
offset = 0L;
currentStart = System.currentTimeMillis();
isStopped = true;
}

public void start()
{
if(isStopped)
{
th = new Thread(this);
th.start();
currentStart = System.currentTimeMillis() - offset;
}

isStopped = false;
}

public void stop()
{
if(!isStopped)
{
th =null;
offset = System.currentTimeMillis() - currentStart;
}
isStopped = true;
}

public long getTime()
{
if(!isStopped)
return System.currentTimeMillis() - currentStart;
else
return offset;
}

@Override
public void run() {
while(!isStopped)
{
System.out.print("\rTime: "+ getTime());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

StopwatchTest.java

public class StopwatchTest {
public static void main(String[] args) {
Stopwatch sw = new Stopwatch();



System.out.println("\nStarting Stopwatch: ");
sw.start();
sleep(2000);
sw.stop();
System.out.println("\nStopwatch Stopped. ");

sleep(2000);

System.out.println("\nStarting Stopwatch: ");
sw.start();
sleep(2000);
sw.stop();
System.out.println("\nStopwatch Stopped. ");

}

public static void sleep(int time)
{
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

References:


Encapsulating the Thread Logic in Stopwatch (Part 2) was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.


This content originally appeared on Level Up Coding - Medium and was authored by Rajtilak Pal


Print Share Comment Cite Upload Translate Updates
APA

Rajtilak Pal | Sciencx (2021-03-26T12:23:03+00:00) Encapsulating the Thread Logic in Stopwatch (Part 2). Retrieved from https://www.scien.cx/2021/03/26/encapsulating-the-thread-logic-in-stopwatch-part-2/

MLA
" » Encapsulating the Thread Logic in Stopwatch (Part 2)." Rajtilak Pal | Sciencx - Friday March 26, 2021, https://www.scien.cx/2021/03/26/encapsulating-the-thread-logic-in-stopwatch-part-2/
HARVARD
Rajtilak Pal | Sciencx Friday March 26, 2021 » Encapsulating the Thread Logic in Stopwatch (Part 2)., viewed ,<https://www.scien.cx/2021/03/26/encapsulating-the-thread-logic-in-stopwatch-part-2/>
VANCOUVER
Rajtilak Pal | Sciencx - » Encapsulating the Thread Logic in Stopwatch (Part 2). [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/03/26/encapsulating-the-thread-logic-in-stopwatch-part-2/
CHICAGO
" » Encapsulating the Thread Logic in Stopwatch (Part 2)." Rajtilak Pal | Sciencx - Accessed . https://www.scien.cx/2021/03/26/encapsulating-the-thread-logic-in-stopwatch-part-2/
IEEE
" » Encapsulating the Thread Logic in Stopwatch (Part 2)." Rajtilak Pal | Sciencx [Online]. Available: https://www.scien.cx/2021/03/26/encapsulating-the-thread-logic-in-stopwatch-part-2/. [Accessed: ]
rf:citation
» Encapsulating the Thread Logic in Stopwatch (Part 2) | Rajtilak Pal | Sciencx | https://www.scien.cx/2021/03/26/encapsulating-the-thread-logic-in-stopwatch-part-2/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.