I'm trying to diagnose convoluted multithreading operations in java.
I want to use the debug perspective to do so, but I encounter the following issue :
Expected behavior :
When pausing a thread (through the Debug view), the "Variables" view should show the variables
as seen by the thread I paused.
Using the Step over / step into operation multiple times should not modify variables in the thread.
Code (Using java 17):
package fr.fgoux.debugbugdemo;
public class DebugDemoMain
{
public int t;
public DebugDemoMain()
{
this.t = 0;
}
public static void main(final String[] args)
{
final DebugDemoMain demo = new DebugDemoMain();
final Thread t1 = new Thread(new Runnable() {
#Override
public void run()
{
for (int i = 0; i < 100; i++)
{
try
{
Thread.sleep(5);
} catch (final InterruptedException e)
{
e.printStackTrace();
}
demo.t++;
}
System.out.println("Write terminated");
}
});
final Thread t2 = new Thread(new Runnable() {
#Override
public void run()
{
while (demo.t != 100)
{
}
System.out.println("READ terminated");
}
});
t1.start();
t2.start();
try
{
t1.join();
t2.join();
} catch (final InterruptedException e)
{
e.printStackTrace();
}
System.out.println("END");
}
}
Behavior :
When I run this in debug mode, I get the output :
Write terminated
And the other thread keeps running.
If I pause the running thread, the debugger shows me it's stuck at "while (demo.t != 100)".
But the "variables" tab shows me t=100.
If I resume / pause this thread, it stays at the "while (demo.t != 100)" and keeps running.
If I press a step by step button, the thread execution line jumps out of the while loop, and then If I resume execution, the thread terminates with "READ terminated".
Personnal interpretation :
The reading thread that does the "demo.t != 100" caches the variable demo.t so that it does not notice that the other thread changed demo.t value (which is expected since there is no synchronization). It cannot make progress.
The "Variables" view does not show locally cached variables of the thread, but only some global representation of the variables (maybe in the shared memory).
The step by step operations cause the thread to update it's cache from the shared memory.
Question :
Is there a better debugging tool that would allow me to show these cached variables and diagnose these issues ?
Related
I try to restart thread but synchronized block in thread keep locked after restarted. I shouldn't change socket properties because some processes take too long but when network connection lost it hangs forever. I try to use InterruptedException but it doesn't work. Is there any way to release this lock?
public static void main(String[] args) {
try {
synchronizedBlock t1 = new synchronizedBlock();
t1.start();
Thread.sleep(500);
t1.cancel();
t1 = new synchronizedBlock();
t1.start();
} catch (Exception e) {
e.printStackTrace();
}
while (true) {
}
}
public class synchronizedBlock extends Thread {
boolean isRunning = true;
boolean isRunning2 = true;
public static Object[] locks = new Object[5];
public synchronizedBlock() {
for (Integer i = 0; i < 5; i++) {
synchronizedBlock.locks[i] = i;
}
}
public void cancel() {
isRunning = false;
interrupt();
}
public void socketProces() {
while (isRunning2) {
}
}
public void proces(int index) {
try {
synchronized (locks[index]) {
System.out.println("Synchronized Block Begin");
socketProces();
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void run() {
try {
System.out.println("Run begin");
while (isRunning) {
proces(1);
}
Thread.sleep(1);
} catch (InterruptedException e) {
//Do Something
} catch (Exception e) {
e.printStackTrace();
}
}
}
Result:
Run begin
Synchronized Block Begin
Run begin
When you start the synchronizedBlock thread you'll get a stack trace like this I think:
run -> proces -> socketProcess.
Then because isRunning2 = true, the thread will enter an infinite loop in socketProcess and never terminate.
Keep in mind that in Java there is no such thing as 'restarting' a thread. Once started, a thread can never be restarted. Indeed, you are creating two sycnchronizedBlock objects, not restarting a single object.
As a side note, it is generally problematic to overwrite static state in a class constructor, as you're doing with the locks variable, without synchronization.
The issue here is the Integer cache which is used in the for loop to initialize the synchronizedBlock.locks array:
for (Integer i = 0; i < 5; i++) {
synchronizedBlock.locks[i] = i;
}
When this code is run again, due to the constructor of the second synchronizedBlock, the synchronizedBlock.locks array contains the same Integer instances which where created when this for loop was executed for the first time. This means that the synchronized (locks[index]) lock will be on the same Integer object. As you have already one thread holding the lock for the Integer(1) object, the second thread waits outside the lock waiting for it to be released.
This is also problematic in combination with the fact that the first thread is not terminating. Your method
public void socketProces() {
while (isRunning2) {
}
}
is an endless loop as you don't change the value of isRunning2, ever. Also, the interrupt() method itself does not stop any thread. Instead, it sets just an internal flag in the Thread class, which can be checked with isInterrupted() and interrupted(). You have to check this flag and react on it like "Oh, someone wants me to stop, so I stop now".
To solve your problem you should at least quit your thread when the "isInterrupted" flag of the Thread instance is set. You can do it like this:
public void socketProces() {
while (isRunning2) {
if (Thread.interrupted()) {
return;
}
}
}
Instead of returning from socketProces() normally you could throw an InterruptedException like other methods do.
Also, depending on how you want to initialize/use the instances you want to lock on with synchronized(...), you might want to consider on how you create/fill the synchronizedBlock.locks array and which objects you want to use (the Integer cache might be problematic here). It depends on you if the creation of a new synchronizedBlock instance will/should/shouldn't create new objects to lock on in the synchronizedBlock.locks array.
tl, dr;
I have a GUI thread that creates an object of another class (the seconds class has implemented Runnable, but here we don't execute the run() method, instead, we call a normal method) and calls a method. In that method, the first thread (current thread) is called again (to show sth on the LCD), then sends some data to the Internet, and waits 3 seconds for the server response. The problem is that the information is printed after 3 seconds. I know about the stack and program counter, but I wonder if there is another option that I can do my job.
I have the main method, which runs 3 threads (for short, I just write the requisite code. Tell me to add more, if needed):
public static void main(String[] args) throws UnknownHostException, InterruptedException {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
GUI.getInstance().setVisible(true); //GUI is singleton, using swing and JFrame
} catch (Exception e) {
e.printStackTrace();
}
}
});
MQTTConnection.getInstance().tryToConnect(); //It's the connection class, which has a thread (the thread is handled by a library that keeps the connection alive. I have no threads there) and is a singleton too.
Thread t1 = new Thread(new SendDataThread()); //A thread which sends some data every 20 seconds.
t1.start();
}
And in SendDataThread, I have a function that creates some random data and sends them (using the MQTTConnection class).
This is the SendDataThread:
public class SendDataThread implements Runnable {
public void sendLog() {
boolean serverOnline = false;
StringBuilder data = new StringBuilder();
data.append(createData());
GUI.getInstance().printNeutral(data.toString()); //Prints BLACK on a `JTextPane`
if(MQTTConnection.getInstance().publishLog(MQTTConnection.getInstance().MQTT_PUBLISH_ESP_SEND_LOG, data.toString())) //This line has a 3 second timeout. If the server doesn't respond, it will return false. I've added the 3 seconds timeout too. Please continue reading.
serverOnline = true;
if(serverOnline)
GUI.getInstance().printOK("Server Submitted"); //Prints in GREEN
else
GUI.getInstance().printProblem("Check your connection!"); //Prints in RED
GUI.getInstance().printNeutral("-------------------------------------------------");
}
#Override
public void run() {
while(true) {
sendLog();
try {
Thread.sleep(20000); //sleeps 20 about seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//.....
}
And this is the 3 seconds timeout method, in MQTTConnection:
boolean publishLog(String topic, String data){
mqtt_responds = false;
publish(topic, data);
System.out.println("MQTT is connected");
long lastTime = System.currentTimeMillis();
while(System.currentTimeMillis() - lastTime < callback_timeout) {
if(mqtt_responds){
mqtt_responds = false;
System.out.println("Server submitted");
return true;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Timeout");
return false;
}
Till now, everything work right. The problem starts where I have a button in the GUI class, which the user can manually send random logs:
JButton sendLogBtn = new JButton("Send Log");
sendLogBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
SendDataThread sdt = new SendDataThread();
sdt.sendLog();
}
});
sendLogBtn.setBounds(10, 331, 89, 23);
panel.add(sendLogBtn);
This button creates an object of SendDataThread and calls the sendLog() method. The issue happens here: after sendLog() is called, sendLog(), calls this GUI thread again:
--> GUI.getInstance().printNeutral(data.toString()); //Prints BLACK on a `JTextPane`
But the log is printed after 3 seconds (After the sendLog() method has finished working, the timeout!)
How can I fix this?
In the button's actionPerformed you are calling sendLog. sendLog does exactly what you said, ie reports some logs and waits about 3 seconds (assuming callback_timeout is about equal to 3000).
To fix this, you need to make sure that the 3sec blocking is not on the EDT and also to make sure that the logs are instead posted on the EDT.
As a quick workaround you can do:
sendLogBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Thread(() -> new SendDataThread().sendLog()).start();
}
});
and then, as always, post your logs in the EDT like for example:
SwingUtilities.invokeLater(() -> GUI.getInstance().printNeutral(...));
AND
SwingUtilities.invokeLater(() -> GUI.getInstance().printProblem(...));
AND
SwingUtilities.invokeLater(() -> GUI.getInstance().printOk(...));
As for the question in your comment, I don't really understand what you are asking, but I should say that (as far as I know) the EDT is a Thread where all the Swing code is (and should be) posted on for execution. This way the Swing code does not have to be synchronized, because all GUI related stuff is executed sequentially (on the EDT). AWT for example was not intended to be single threaded as far as I know. Swing is however single threaded.
Runnable updateSeekbar=new Runnable() {
#Override
public void run() {
try{
while (true) {
if (!isPlayerDead) {
Log.d("Threads", "Thread is running successfully.");
int progress=mediaPlayer.getCurrentPosition();
seekBar.setProgress(progress);
Log.d("Seekbar",seekBar.getProgress()+"");
Log.d("MediaProgress",mediaPlayer.getCurrentPosition()+"");
String s=modifyTime(mediaPlayer.getCurrentPosition() / 1000 / 60) + ":" + modifyTime((mediaPlayer.getCurrentPosition() / 1000) % 60);
progressTime.setText(s);
}
}
}
catch (Exception e){
e.printStackTrace();
}
}
};
Executor executor=new Executor() {
#Override
public void execute(Runnable command) {
Thread thread=new Thread(command);
thread.start();
}
};
executor.execute(updateSeekbar);
Actually the problem is that the thread dies before the mediaplayer can send updated position. I have made the thread in an endless while loop but still it dies. How can I make it run infinitely till the activity gets destroyed.
The thread only runs for a couple of seconds and then dies. I want it to run infinitely till the activity gets destroyed. All suggestions are welcome.
when mediaPlayer isn't in proper state and you try to call some improper method then some Exception may be thrown, and you are catching it OUTside while(true) loop. try to move try{}catch inside while(true), then your Thread will run infinitely
#Override
public void run() {
while (true) {
try{
if (!isPlayerDead) {
// current code
}
}
catch (Exception e){
e.printStackTrace();
}
SystemClock.sleep(20); // some bonus line
} // end of while
}
btw. give some rest for UI between iterations, e.g. by putting SystemClock.sleep(20); after every calculation (last line before closing bracket). you don't need so often progress refreshing, in current code it may happen even few times more often than system is capable to draw (in most often 60Hz case)
class Test {
boolean isFirstThread = true;
private synchronized void printer(int threadNo) {
if(isFirstThread) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isFirstThread = false;
System.out.println(threadNo);
}
public void starter() {
new Thread(){
#Override()
public void run() {
printer(0);
}
}.start();
new Thread(){
#Override()
public void run() {
printer(1);
}
}.start();
new Thread(){
#Override()
public void run() {
printer(2);
}
}.start();
new Thread(){
#Override()
public void run() {
printer(3);
}
}.start();
}
}
In the above code, when i call starter from main. I have created four new Threads to call a synchronized function. I know the order of execution of the threads can't be predicted. Unless they all wait for some time, so that first thread can finish and come out of the synchronized block. In which case I expect all threads to be held in a queue so i expected the answer as
0
1
2
3
But consistently(I ran the program more than 20 times) I was getting the output as
0
3
2
1
Which means that the threads are being held in a stack instead of a queue. Why is it so? Every answer in the google result says it is a queue but I am getting it as a stack. I would like to know the reason behind for holding the threads in stack(which is counter intuitive) instead of queue?
The order in which threads start is up to the OS, it is not specified in the Java Language Spec. You call start in the main thread, but when the new thread gets allocated and when it begins processing its Runnable or run method is left to the OS' scheduler to decide.
Be careful not to rely on the order in which threads happen to start.
By default, Eclipse breakpoints are suspending only one thread. This causes application continues to run when I am thinking on breakpoint.
The is another mode for breakpoint - to suspend entire VM. This stops all thread but apparently I am unable to resume an execution or execution behaves differently on resume.
Is it possible to do normal suspend on breakpoints in Eclipse?
UPDATE
There is definitely not my problem, but Eclipse/JVM/other human bug. I made a simple example without any thread interaction:
package tests;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Try_EclipseMultithreadedBreakpoint {
private static final Logger log = LoggerFactory.getLogger(Try_EclipseMultithreadedBreakpoint.class);
public static class Thread1 extends Thread {
public Thread1() {
setName("Thread1");
}
#Override
public void run() {
for(int i=0; i<10; ++i) {
log.info("tick {}", i);
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
}
}
}
}
public static class Thread2 extends Thread {
public Thread2() {
setName("Thread2");
}
#Override
public void run() {
for(int i=0; i<15; ++i) {
log.info("tick {}", i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
public static void main(String[] args) {
new Thread1().start();
new Thread2().start();
}
}
then I put an exception into second thread (Thread2):
then I have few breakpoint hits and resumes, then removed breakpoint and resumed, and application hanged.
Below is it's hung state:
as you see by output, thread 1 was not resumed. It printed only one tick and stopped. And it is not waiting for some monitor as reported by Eclipse, it is suspended.
Note, that I didn't set any breakpoints in thread 1, I set them only in thread 2.
Simultaneously, some "Finalizer" thread is waiting for some internal resource.
Also, I noticed, that after breakpoint hit, I was required to press resume several times before it actually resumed.
Select the item as shown on the screenshot and press F8