This a much simplified version of my multithreading project and its just a way to replicate the issue in a simpler way for easy understanding.
So I have two classes startSession.java and main.java
what I am trying to do is to send a variable from startSession.java to main.java and Im also using multithreading. However, the problem I am facing is that everytime I try to retrieve the variable inside main I get a null value.
Inside startSession theres the run method and Setter(setSessionKey(String sess)) and getter(getSessionKey()) methods. I hardcoded a variable to test.
The get method only works inside the run method but when I call getSessionKey() from inside main I get a null as seen below. However, this is only a problem when I am using multithreading. When I dont use multithreading and instead just call the run method from inside main, the variable Im looking for is no longer null.
My question is there a way to send a variable from startSession to main while using multithreading ?
thank you
startSession.java
public class startSession extends Thread {
static String sessionKey;
public void run() {
String createdSession = "83248329";
setSessionKey(createdSession);
System.out.println("Inside run method: " getSessionKey());
}
public String getSessionKey() {
return sessionKey;
}
public void setSessionKey(String sess) {
sessionKey = sess;
}
}
main.java
package com.Server;
public class Main {
static String session;
public static void main(String[] args) throws InterruptedException {
startSession startSession = new startSession();
startSession.start();
session = startSession.getSessionKey();
System.out.println("Inside Main: " session);
}
}
with multithreading
without multithreading
CodePudding user response:
Use Callback to get sessionKey:
public class startSession extends Thread {
static String sessionKey;
SessionKeyCallBack sessionKeyCallBack;
public startSession()
{
getSessionKey();
}
public void setSessionKeyCallBack(SessionKeyCallBack sessionKeyCallBack) {
this.sessionKeyCallBack = sessionKeyCallBack;
}
public void run(){
String createdSession= "83248329";
setSessionKey(createdSession);
System.out.println("Inside run method: " getSessionKey());
if (sessionKeyCallBack != null) {
sessionKeyCallBack.onSetSessionKey(sessionKey);
}
}
public String getSessionKey() {
return sessionKey;
}
public void setSessionKey(String sess) {
sessionKey = sess;
}
interface SessionKeyCallBack {
void onSetSessionKey(String sessionKey);
}
}
you will get sessionKey on callback:
public class Main {
static String session;
public static void main(String[] args) throws InterruptedException {
startSession startSession= new startSession();
startSession.setSessionKeyCallBack(new startSession.SessionKeyCallBack() {
@Override
public void onSetSessionKey(String sessionKey) {
System.out.println("Inside Main: " sessionKey);
}
});
startSession.start();
}
}
CodePudding user response:
Use a BlockingQueue whereby the Thread (Producer) will add
to the shared queue and the Main (Consumer) will block on the take
main
public static void main(String[] args) throws Exception {
BlockingQueue queue = new ArrayBlockingQueue(1024);
StartSession producer = new StartSession(queue);
....
System.out.println(queue.take());
startSession
String createdSession= "83248329";
queue.add(createdSession);
see https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/BlockingQueue.html
and https://jenkov.com/tutorials/java-util-concurrent/blockingqueue.html
CodePudding user response:
The easiest answer is: The thread has not initialized the session yet.
When I run your pasted code this is also the true one. I modified your example code so it works correctly. Please bear in mind that in a real world implementation you should not do it with one sleep but either via a callback or some waiting / timeout mechanism.
import java.lang.Thread;
public class Main {
static String session;
public static void main(String[] args) throws InterruptedException {
Main m = new Main();
}
public Main() {
StartSession startSession = new StartSession();
startSession.start();
// not working because the thread has not assigned the session yet
session = startSession.getSessionKey();
System.out.println("Inside Main 1: " session);
// let the main thread sleep for a second for the startSession to catch up
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// do nothing
}
// working because the thread had enough time to assign the session
session = startSession.getSessionKey();
System.out.println("Inside Main 2: " session);
}
public class StartSession extends Thread {
// I strongly recommend to use the volatile modifier, see https://stackoverflow.com/questions/2423622/volatile-vs-static-in-java
volatile static String sessionKey;
public void run() {
String createdSession= "83248329";
setSessionKey(createdSession);
System.out.println("Inside run method: " getSessionKey());
System.out.println("Thread run finished... ");
}
public String getSessionKey() {
return sessionKey;
}
public void setSessionKey(String sess) {
sessionKey = sess;
}
}
}
Also please do add the volatile modifier to your static variable otherwise you may encounter problems very hard to understand (in my code there is a comment linking to an explanation).