I have a class that calls a method from another class which uses a thread as it is somewhat a intensive task. The Thread is responsible for looking through a dictionary to find a matching word. When a word is found it should/does set a local variable in that class. I can see that it is successfully setting this String because it say's so in the log. However, whenever I try and retrieve this String from another class and set the TextView to the value of this String, Nothing happens.
I'm using the Thread because a lot of frames were being skipped. However, when I don't use the thread it works as it is suppose to(Minus the frames being skipped).
Here is the method with the thread:
public String checkLetters() {
new Thread(new Runnable() {
#Override
public void run() {
//Finding the directory on SD Card
File sdcard = Environment.getExternalStorageDirectory();
//Retrieve the text file
File file = new File(sdcard,"NewEnglishDictionary.txt");
try {
BufferedReader bufferRead = new BufferedReader(new FileReader(file),24396);
String line; //= "";
//While no word found keep looping
while (wholeWordFound == false ) {
line = bufferRead.readLine();
Log.d("ResolveWord", "Current Line: " + line);
wordReturned = workOutWord(line);
setWord(wordReturned);
}
String value = getWord().toString().toLowerCase();
Log.d("Value of setWord: ", " equals: "+ value);
bufferRead.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
return wordReturned;
}
And calling to retrieve the variable that has been set (according to the log)
tv_WordFound.setText(fixAnagram.getWord());
And the method which is suppose to return it:
public String getWord() {
Log.d("Test", "getWord: " + wordReturned);
return wordReturned;
}
Is there something I'm missing with threads?
Cheers for any help. Logcat itself gives me no clue to where the error lies.
you need to using callback or interface or asynctask for this case. Because your Thread inside checkLetters method will end after your checkLetters. That means if you call getWord() immediately after calling checkLetters, you can only get the previous checking result.
The Memory model of Java does not guarantee, that values set by one thread are immediately visible by another thread.
To guarantee this, you either must declare the variable as "volatile" or have a synchronized involved (e.g. have the getter and setter method with the keyword synchronized).
e.g.
private volatile String word;
or
public synchronized String getWord() { return word; }
public synchronized void setWord(String w) { word = w; }
Related
I'm a small java developer currently working on a discord bot that I made in Java. one of the features of my bot is to simply have a leveling system whenever anyone sends a message (and other conditions but this is irrelevant for the problem I'm encountering).
Whenever someone sends a message an event is fired and a thread is created to compute how much exp the user should gain. and eventually, the function to edit the storage file is called.
which works fine when called sparsely. but if two threads try to write on the file at once, the file usually gets deleted or truncated. either of these two cases being undesired behavior
I then tried to make a queuing system that worked for over 24h but still failed once so it is more stable in a way. I only know the basics of how threads work so I may've skipped over an important thing that causes the problem
the function looks like this
Thread editingThread = null;
public boolean editThreadStarted = false;
HashMap<String, String> queue = new HashMap<>();
public final boolean editParameter(String key, String value) {
queue.put(key, value);
if(!editThreadStarted) {
editingThread = new Thread(new Runnable() {
#Override
public void run() {
while(queue.keySet().size() > 0) {
String key = (String) queue.keySet().toArray()[0];
String value = queue.get(key);
File inputFile = getFile();
File tempFile = new File(getFile().getName() + ".temp");
try {
tempFile.createNewFile();
} catch (IOException e) {
DemiConsole.error("Failed to create temp file");
handleTrace(e);
continue;
}
//System.out.println("tempFile.isFile = " + tempFile.isFile());
try (BufferedReader reader = new BufferedReader(new FileReader(inputFile)); BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))){
String currentLine;
while((currentLine = reader.readLine()) != null) {
String trimmedLine = currentLine.trim();
if(trimmedLine.startsWith(key)) {
writer.write(key + ":" + value + System.getProperty("line.separator"));
continue;
}
writer.write(currentLine + System.getProperty("line.separator"));
}
writer.close();
reader.close();
inputFile.delete();
tempFile.renameTo(inputFile);
} catch (IOException e) {
DemiConsole.error("Caught an IO exception while attempting to edit parameter ("+key+") in file ("+getFile().getName()+"), returning false");
handleTrace(e);
continue;
}
queue.remove(key);
}
editThreadStarted = false;
}
});
editThreadStarted = true;
editingThread.start();
}
return true;
}
getFile() returns the file the function is meant to write to
the file format is
memberid1:expamount
memberid2:expamount
memberid3:expamount
memberid4:expamount
the way the editing works is by creating a temporary file to which i will write all of the original file's data line by line, checking if the memberid matches with what i want to edit, if it does, then instead of writing the original file's line, i will write the new edited line with the new expamount instead, before continuing on with the rest of the lines. Once that is done, the original file is deleted and the temporary file is renamed to the original file, replacing it.
This function will always be called asynchronously so making the whole thing synchronous is not an option.
Thanks in advance
Edit(1) :
I've been suggested to use semaphores and after digging a little into it (i never heard of semaphores before) it seems to be a really good option and would remove the need for a queue, simply aquire in the beginning and release at the end, nothing more required!
I ended up using semaphores as per user207421's suggestions and it seems to work perfectly
I simply put delays between each line write to artificially make the task longer and make it easier to have multiple threads trying to write at once, and they all wait for their turns!
Thanks
I have a small java program, written in Eclipse using WindowBuilder, which works on reading data from UTF-8 text files and writing them into a database. To maintain the GUI's responsiveness, I use a swing worker thread, executed when clicking on a button.
btnex.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
worker = new SwingWorker<Void, Void>() {
public Void doInBackground() {
String[] content = Reader.getContent(file);
//do something with the content, if something goes wrong, set error to true.
return null;
}
public void done() {
if (!error) {
//handle error
}
};
worker.execute();
The function getContent in the class Reader extracts data from the file into the string array.
public static String[] getContent (String dbfile) {
try {
String[] lines = null;
String[] linesplit = null;
String store = "";
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(dbfile), "UTF8"));
String line = "";
line = reader.readLine();
linesplit = line.split(";");
while (linesplit.length > 1 && !line.equals(null)) {
for (int i = 0; i < linesplit.size(); i++) {
store += StringFormer.decrypt(linesplit[i]) + " ";
} //StringFormer is another class written by me, just for decrypting the string
store += "\n";
line = reader.readLine();
if (line.equals(null)) break;
linesplit = line.split(";");
}
reader.close();
lines = store.split("\n");
return lines;
} catch (Exception ex) { //...
}
}
When I try to run my program and click the button, the program does not work correctly. So I run the program in debug mode, and as a result, the thead does not finish but somehow exits before finishing all work. This happens in getContent, after leaving the while loop but before working on reader.close(). Before leaving the while loop, the call stack in the debug view contains the calls of the button click and of getContent, next to others, but once I leave the loop, the two mentioned above are dropped and the next top stack member names the base swing worker class: SwingWorker$2(FutureTask).run.
Does anyone know, why the program does not finish the written work flow? I work with multiple threads in the program, but never two background threads are running at the same time.
I found the answer myself:
The line if(line.equals(null) throws a NullPointerException. line is null when nothing more can be read out of the file, but the function equals requires that the compared variable is defined. Since line was null, equals threw the exception without me noticing it. The line has to be if(line==null).
How to write in a file with threads ? Each file should be 100 lines, each line length is 100 characters. This work must perform threads and I\O.
My code:
public class CustomThread extends Thread{
private Thread t;
private String threadName;
CustomThread(String threadName){
this.threadName = threadName;
}
public void run () {
if (t == null)
{
t = new Thread (this);
}
add(threadName);
}
public synchronized void add(String threadName){
File f = new File(threadName + ".txt");
if (!f.exists()) {
try {
f.createNewFile();
} catch (IOException e) {
e.printStackTrace();
System.out.println("File does not exists!");
}
}
FileWriter fw = null;
try {
fw = new FileWriter(f);
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) {
fw.write(threadName);
fw.write('\n');
}
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("File does not exists!");
}
}
}
My code is correct ? I need to create file with 100 lines and 100 characters. Сharacter must depend on the file name. If I create a file named 1, and the name of the filling must be 1. Thanks.
Your code looks correct as per your requirement which is writing 100 lines and each line containing 100 characters. The assumption is, name of the thread will be single character, because your are writing threadName to the file. I have few closing suggestion to complete your implementation. They test it by yourself. If your find any issue, do comment.
To have each line 100 characters, you need to move new line characters statement to outer loop.
Once your finishing writing writing all the data to file, do flush() and close() the file, for saving it.
You are creating the file with threadName, You might want to add the starting path location for the file to be created.
Obviously you are missing main() method. Create object of the class and start() the thread.
You don't need to create a separate Thread instance, The run() method will be executed in a separate thread because you are extending Thread class.
I am sending a some json to a php page from my java application which echos "finished" if successful. The json and php are working great. I am trying to pass a string to a thread and then change the value of the string to the echo from the php in the thread, and when the Thread is finished I want to use an if statement to determine if the URL connection was successfully completed... which it is I just can't get the value of the string from the Thread.
here is my code:
main.java
final String line = "unfinished";
Thread iURL = new instrURL(line, jsonArray);
iURL.start();
while(iURL.isAlive())
{
System.out.println("In wait loop");
}
System.out.println(line);
if(line.trim() == "finished")
{
System.out.println("Made it to finished");
}
else
{
System.out.println("Did not make it to finished");
}
instrURL.java
public class instrURL extends Thread{
String line;
String jsonArray;
public instrURL(String line, String jsonArray)
{
this.line = line;
this.jsonArray = jsonArray;
}
public void run()
{
try
{
URL url = new URL("http://fake.php?jsonArray="+URLEncoder.encode(jsonArray, "UTF-8"));
URLConnection conn = url.openConnection();
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
line = rd.readLine();
System.out.println(line);
rd.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
the console:
In wait while loop
In wait while loop
...
...
...
In wait while loop
finished
In wait while loop
In wait while loop
In wait while loop
unfinished
Did not make it to finished
As you can see from the console the Thread gets the finished, but once outside of the Thread the strings value is still unfinished.
Any help would be greatly appreciated.
You have at least four different String reference variables with the name line in your process, and updates to one won't be reflected in the other ones, which is why your program doesn't behave as expected:
final String line = "unfinished"; in main.java - looks like a
local variable on the stack
instrURL(String line, - a paramter to
the instrURL constructor
instrURL.line a member in the instrURL
class
String line; a local in the run() method in instrURL
All of these are distinct references, so assigning to one will not affect any of the others. Even beyond that, I don't see any assignments at all to any of the flavors of line in the instrURL class.
Generally speaking you should use established inter-thread communication methods such as Future, or shared statics under a lock, but probably the closest thing to what you want is to declare a static volatile String line somewhere, and refer to it in both main and your thread class, and remove all other copies of line.
Java compare string with equals method not with ==
if(null!line && line.trim().equals("finished"))
{
System.out.println("Made it to finished");
}
Inside run method you are not reading data from buffered reader and not changing the value of line, that's why you are getting same value as "unfinished", you need to read data like this
String currentLine
while ((currentLine = br.readLine()) != null) {
System.out.println(sCurrentLine);
}
after reading data from stream , set value in line string as
line="finished";
I am new to Multithreading and synchronization in java. I am trying to achieve a task in which i am given 5 files, each file will be read by one particular thread. Every thread should read one line from file then forward execution to next thread and so on. When all 5 threads read the first line, then again start from thread 1 running line no. 2 of file 1 and so on.
Thread ReadThread1 = new Thread(new ReadFile(0));
Thread ReadThread2 = new Thread(new ReadFile(1));
Thread ReadThread3 = new Thread(new ReadFile(2));
Thread ReadThread4 = new Thread(new ReadFile(3));
Thread ReadThread5 = new Thread(new ReadFile(4));
// starting all the threads
ReadThread1.start();
ReadThread2.start();
ReadThread3.start();
ReadThread4.start();
ReadThread5.start();
and in ReadFile (which implements Runnable, in the run method, i am trying to synchronize on bufferreader object.
BufferedReader br = null;
String sCurrentLine;
String filename="Source/"+files[fileno];
br = new BufferedReader(new FileReader(filename));
synchronized(br)
{
while ((sCurrentLine = br.readLine()) != null) {
int f=fileno+1;
System.out.print("File No."+f);
System.out.println("-->"+sCurrentLine);
br.notifyAll();
// some thing needs to be dine here i guess
}}
Need Help
Though this is not an ideal scenario for using multi-threading but as this is assignment I am putting one solution that works. The threads will execute sequentially and there are few point to note:
Current thread cannot move ahead to read the line in the file until and unless its immediately previous thread is done as they are supposed to read in round-robin fashion.
After current thread is done reading the line it must notify the other thread else that thread will wait forever.
I have tested this code with some files in temp package and it was able to read the lines in round robin fashion. I believe Phaser can also be used to solve this problem.
public class FileReaderRoundRobinNew {
public Object[] locks;
private static class LinePrinterJob implements Runnable {
private final Object currentLock;
private final Object nextLock;
BufferedReader bufferedReader = null;
public LinePrinterJob(String fileToRead, Object currentLock, Object nextLock) {
this.currentLock = currentLock;
this.nextLock = nextLock;
try {
this.bufferedReader = new BufferedReader(new FileReader(fileToRead));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
#Override
public void run() {
/*
* Few points to be noted:
* 1. Current thread cannot move ahead to read the line in the file until and unless its immediately previous thread is done as they are supposed to read in round-robin fashion.
* 2. After current thread is done reading the line it must notify the other thread else that thread will wait forever.
* */
String currentLine;
synchronized(currentLock) {
try {
while ( (currentLine = bufferedReader.readLine()) != null) {
try {
currentLock.wait();
System.out.println(currentLine);
}
catch(InterruptedException e) {}
synchronized(nextLock) {
nextLock.notify();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
synchronized(nextLock) {
nextLock.notify(); /// Ensures all threads exit at the end
}
}
}
public FileReaderRoundRobinNew(int numberOfFilesToRead) {
locks = new Object[numberOfFilesToRead];
int i;
String fileLocation = "src/temp/";
//Initialize lock instances in array.
for(i = 0; i < numberOfFilesToRead; ++i) locks[i] = new Object();
//Create threads
int j;
for(j=0; j<(numberOfFilesToRead-1); j++ ){
Thread linePrinterThread = new Thread(new LinePrinterJob(fileLocation + "Temp" + j,locks[j],locks[j+1]));
linePrinterThread.start();
}
Thread lastLinePrinterThread = new Thread(new LinePrinterJob(fileLocation + "Temp" + j,locks[numberOfFilesToRead-1],locks[0]));
lastLinePrinterThread.start();
}
public void startPrinting() {
synchronized (locks[0]) {
locks[0].notify();
}
}
public static void main(String[] args) {
FileReaderRoundRobinNew fileReaderRoundRobin = new FileReaderRoundRobinNew(4);
fileReaderRoundRobin.startPrinting();
}
}
If the only objective is to read the files in round-robin fashion and not strictly in same order then we can also use Phaser. In this case the order in which files are read is not always same, for example if we have four files (F1, F2, F3 and F4) then in first phase it can read them as F1-F2-F3-F4 but in next one it can read them as F2-F1-F4-F3. I am still putting this solution for sake of completion.
public class FileReaderRoundRobinUsingPhaser {
final List<Runnable> tasks = new ArrayList<>();
final int numberOfLinesToRead;
private static class LinePrinterJob implements Runnable {
private BufferedReader bufferedReader;
public LinePrinterJob(BufferedReader bufferedReader) {
this.bufferedReader = bufferedReader;
}
#Override
public void run() {
String currentLine;
try {
currentLine = bufferedReader.readLine();
System.out.println(currentLine);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public FileReaderRoundRobinUsingPhaser(int numberOfFilesToRead, int numberOfLinesToRead) {
this.numberOfLinesToRead = numberOfLinesToRead;
String fileLocation = "src/temp/";
for(int j=0; j<(numberOfFilesToRead-1); j++ ){
try {
tasks.add(new LinePrinterJob(new BufferedReader(new FileReader(fileLocation + "Temp" + j))));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
public void startPrinting( ) {
final Phaser phaser = new Phaser(1){
#Override
protected boolean onAdvance(int phase, int registeredParties) {
System.out.println("Phase Number: " + phase +" Registeres parties: " + getRegisteredParties() + " Arrived: " + getArrivedParties());
return ( phase >= numberOfLinesToRead || registeredParties == 0);
}
};
for(Runnable task : tasks) {
phaser.register();
new Thread(() -> {
do {
phaser.arriveAndAwaitAdvance();
task.run();
} while(!phaser.isTerminated());
}).start();
}
phaser.arriveAndDeregister();
}
public static void main(String[] args) {
FileReaderRoundRobinUsingPhaser fileReaderRoundRobin = new FileReaderRoundRobinUsingPhaser(4, 4);
fileReaderRoundRobin.startPrinting();
// Files will be accessed in round robin fashion but not exactly in same order always. For example it can read 4 files as 1234 then 1342 or 1243 etc.
}
}
The above example can be modified as per exact requirement. Here the constructor of FileReaderRoundRobinUsingPhaser takes the number of files and number of lines to read from each file. Also the boundary conditions need to be taken into consideration.
You are missing many parts of the puzzle:
you attempt to synchronize on an object local to each thread. This can have no effect and the JVM may even remove the whole locking operation;
you execute notifyAll without a matching wait;
the missing wait must be at the top of the run method, not at the bottom as you indicate.
Altogether, I'm afraid that fixing your code at this point is beyond the scope of one StackOverflow answer. My suggestion is to first familiarize yourself with the core concepts: the semantics of locks in Java, how they interoperate with wait and notify, and the precise semantics of those methods. An Oracle tutorial on the subject would be a nice start.