I hope I can explain the problem in proper way :)
I have an array of object (handleData).I get them from DB. I want to send them to server by calling service for each one individually.
I put the service in a for loop to send all handleData (refer to code) .
Calling service is done a background . the response of each may not come as they sent orderly. and I have to do some update for each handleData I send.
problem : when the response comes I am not sure that if the regarded action (update of record) is done to the exact handleData that I want/sent properly.
private void sendDataOfTemplates() {
ArrayList<FormHandleData> formHandleDatas = FormHandleData.getDatasFromDB(getContext(), 12, EnumDataStatusOfServer.NoSTATUS.getIntValue(),-1);// true means >> to send / -1 means no limit
try {
if (formHandleDatas != null && formHandleDatas.size() != 0) {
for (int i = 0; i < formHandleDatas.size(); i++) {
final FormHandleData handleData = formHandleDatas.get(i);
if (handleData.status_in_server == EnumDataStatusOfServer.OPEN.getIntValue())
if (handleData.status_in_app == EnumDataStatusInApp.SAVED.getIntValue() || handleData.status_in_app == EnumDataStatusInApp.EDITED.getIntValue()) {
ServiceHelper.getInstance().sendDataOfTemplates(new ServiceHelper.ResponseListener() {
#Override
public void onResponse(String response) {
try {
SimpleResponse simple_response = new Gson().fromJson(response, SimpleResponse.class);
if (simple_response.isSuccessful()) {
handleData.status_in_app = EnumDataStatusInApp.SENT.getIntValue();
FormHandleData.UpdateDataTemplatesInDB(handleData, getContext(),false);
} else {
}
} catch (Exception e) {
}
}
#Override
public void onErrorResponse(VolleyError error) {
}
}, handleData);
}
}
}
} catch (Exception e) {
}
}
problem : when the response comes I am not sure that if the regarded action (update of record) is done to the exact handleData that I want/sent properly.
If I understand correctly, you are asking if the surrounding local variable handleData which is being accessed by your anonymous ServiceHelper.ResponseListener subclass will always be the same object instance even though in the next for cycle the value of that variable will be different. The answer is yes. So you don't need to worry.
If you want to know more about how anonymous classes can capture variables from a surrounding scope, please read this part of the Oracle's Java tutorial, which says:
An anonymous class has access to the members of its enclosing class.
An anonymous class cannot access local variables in its enclosing scope that are not declared as final or effectively final.
So the fact that the surrounding variable can be accessed means it is (effectively) final from the perspective of the anonymous class, i.e. it does not change.
Here is a little demonstration using multiple threads:
package de.scrum_master.app;
public class WhoDoesWhat {
private String name;
private final String action;
public WhoDoesWhat(String name, String action) {
this.name = name;
this.action = action;
}
public String getName() {
return name;
}
#Override
public String toString() {
return name + " -> " + action;
}
}
package de.scrum_master.app;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Application {
private static final Random RANDOM = new Random();
public static void main(String[] args) {
List<WhoDoesWhat> peopleDoingSomething = new ArrayList<>();
peopleDoingSomething.add(new WhoDoesWhat("Galileo", "discover moons of Jupiter"));
peopleDoingSomething.add(new WhoDoesWhat("Johannes", "determine the laws of planetary motion"));
peopleDoingSomething.add(new WhoDoesWhat("Albert", "explain the precession of Mercury"));
peopleDoingSomething.add(new WhoDoesWhat("Edwin", "notice something odd about recession speeds of galaxies"));
for (WhoDoesWhat personDoingSomething : peopleDoingSomething) {
new Thread(() -> {
System.out.println("START " + personDoingSomething);
try {
int waitCycles = 1 + RANDOM.nextInt(10);
for (int cycle = 0; cycle < waitCycles; cycle++) {
System.out.println(" " + personDoingSomething.getName() + " is still being busy");
Thread.sleep(250);
}
} catch (InterruptedException e) {
}
System.out.println("STOP " + personDoingSomething);
}).start();
}
}
}
The console log could look like this:
START Johannes -> determine the laws of planetary motion
START Albert -> explain the precession of Mercury
START Galileo -> discover moons of Jupiter
START Edwin -> notice something odd about recession speeds of galaxies
Albert is still being busy
Johannes is still being busy
Edwin is still being busy
Galileo is still being busy
Galileo is still being busy
Edwin is still being busy
Johannes is still being busy
Albert is still being busy
Edwin is still being busy
Galileo is still being busy
Albert is still being busy
STOP Johannes -> determine the laws of planetary motion
Edwin is still being busy
Galileo is still being busy
Albert is still being busy
Galileo is still being busy
STOP Edwin -> notice something odd about recession speeds of galaxies
STOP Albert -> explain the precession of Mercury
Galileo is still being busy
Galileo is still being busy
Galileo is still being busy
STOP Galileo -> discover moons of Jupiter
you can send them one by one when each one is finished like recursive methods. hope this work for you..
problem : when the response comes I am not sure that if the regarded action (update of record) is done to the exact handleData that I want/sent properly.
I know it's an old thread but just wanna help........
In order to find out that the returning handleData corresponds to which element of formHandleDatas ArrayList, you can send an id (which is unique to each one of the elements of the array list) alongside handleData to the server and send it back to the client whenever server returns the result. In this way it will be possible to find the exact handleData. Here I have refactored your code a little bit.
private void sendDataOfTemplates() {
Map<Integer, FormHandleData> formHandleDataMap = FormHandleData.getDatasFromDBAsMap();
try {
if (formHandleDataMap != null && formHandleDataMap.size() != 0) {
formHandleDataMap.forEach((key, handleData) -> {
if (handleData.getStatusInServer() == FormHandleData.EnumDataStatusOfServer.OPEN.ordinal())
if (handleData.getStatusInApp() == FormHandleData.EnumDataStatusInApp.SAVED.ordinal() ||
handleData.getStatusInApp()== FormHandleData.EnumDataStatusInApp.EDITED.ordinal()) {
ServiceHelper.getInstance().sendDataOfTemplates(
new ServiceHelper.ResponseListener() {
#Override
public void onResponse(String response) {
try {
SimpleResponse simpleResponse = new Gson().fromJson(response, SimpleResponse.class);
FormHandleData currentHandleData = formHandleDataMap.get(simpleResponse.getKey());
if (simpleResponse.isSuccessful()) {
currentHandleData.setStatusInApp(FormHandleData.EnumDataStatusInApp.SENT.ordinal());
FormHandleData.UpdateDataTemplatesInDB(currentHandleData, getContext(), false);
} else {
System.out.println("simple response is not successful");
}
} catch (Exception e) {
System.out.println("exception happened while getting simple response:" + e.getMessage());
e.printStackTrace();
}
}
#Override
public void onErrorResponse() {
}
}, handleData);
}
});
}
} catch (Exception e) {
System.out.println("exception happened:" + e.getMessage());
e.printStackTrace();
}
}
here I've used a Map to handle the unique id I mentioned, actually unique id the key of the handleData entry in the map. hope it helps.
Related
Recently I've started looking into multithreading, and I have a question, perhaps more experienced ones could help.
My program creates two parallel threads, each of them prints counts from 0 to 19 (the NumbersPrinter class, which implements the Runnable interface).
class NumbersPrinter implements Runnable {
private Mediator mediator;
private String name;
private int makeActionOnCount;
public NumbersPrinter(Mediator mediator, String name, int makeActionOnCount) {
this.mediator = mediator;
this.name = name;
this.makeActionOnCount = makeActionOnCount;
}
#Override
public void run() {
for(int i = 0; i<20; i++){
try {
synchronized(this.mediator) {
if(this.mediator.actionInProgress.get()) {
System.out.println(name + " waits");
wait();
}
}
System.out.println(this.name + " says " + i);
Thread.sleep(500);
if(i == makeActionOnCount) {
synchronized(this.mediator) {
System.out.println(this.name + " asks Mediator to perform action...");
this.mediator.performAction();
this.mediator.notify();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
When one of the threads reaches a certain number (defined in the makeActionOnCount variable), it starts performing a certain action that stops the execution of the second counter. The action lasts 5 seconds and after that both counters continue to count.
The counters are interconnected through an instance of the Mediator class, the performAcyion() method also belongs to the instance of the Mediator class.
import java.util.concurrent.atomic.AtomicBoolean;
class Mediator {
public AtomicBoolean actionInProgress = new AtomicBoolean(false);
public Mediator() {
}
public void performAction() throws InterruptedException {
actionInProgress.set(true);
System.out.println("Action is being performed");
Thread.sleep(5000);
System.out.println("Action has been performed");
actionInProgress.set(false);
}
}
Here's the Main class:
class Main {
public static void main(String[] args) throws InterruptedException{
Mediator mediator = new Mediator();
NumbersPrinter data = new NumbersPrinter(mediator, "Data", 10);
NumbersPrinter lore = new NumbersPrinter(mediator, "Lore", 5);
Thread oneThread = new Thread(data);
Thread twoThread = new Thread(lore);
System.out.println("Program started");
oneThread.start();
twoThread.start();
oneThread.join();
twoThread.join();
System.out.println("Program ended");
}
The way the program is written now - works fine, but I don't quite understand what exactly should I write in the first synchronized block, because if you delete all content from it, the program still works, since the counter that does not execute the performAction() method stops 'cause the counter cannot access the monitor of the Mediator object 'cause it is busy with the parallel counter. AtomicBoolean variable and checking it also makes no sense.
In other words, I may not use the wait () and notify () constructs at all, as well as the value of the AtomicBoolean variable, and just check access to the Mediator object's monitor every new iteration using an empty synchronized block. But I've heard that an empty synchronized block is a bad practice.
I am asking for help on how to rewrite the program to use the synchronized block and the wait() and notify() methods correctly.
Maybe I'm syncing on the wrong object? How would you solve a similar problem?
Thanks in advance
We are creating a rest application. And we have an edge condition where parallel actions are not supported on same object.
For example :
Not supported in parallel
Request 1 for action XYZ for object A
Request 2 for action XYZ for object A
Request 3 for action ABC for object A
Supported in parallel
Request 1 for action XYZ for object A
Request 2 for action XYZ for object B
Request 3 for action ABC for object C
Now, the object count is not fixed. we can have n number of such objects.
I want that if a request for object A is under progress then other request for object A should wait for existing task on object A to get over.
But I am not able to figure out the algorithm for this purpose.
I could plan for below design but not able to figure out on how to use the locking since all objects can be different.
A queue which stores the entry for object A when request comes.
Entry gets deleted if response is sent
If an entry is already present, then wait for existing request to get over.
If entry not present, then execute immediately.
Now task on object A should not impact the task on object B. So they must accept unique locks.
And also, request cannot go standalone and be queued. Somehow I have to make the current thread sleep so that I can send response to user.
Can anyone guide here?
UPDATED based on comments from my original response
The ideal model for something like that would be using an actor system such as Akka.
But your comment states that this will happen in the context on a REST application where threads will be blocked already by request processing.
In this case, the idea would be using a per-object-guard such as:
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
public class ObjectGuard<K> {
private final ConcurrentMap<K, CountDownLatch> activeTasks = new ConcurrentHashMap<>();
public Guard guardFor(final K key) throws InterruptedException {
if (key == null) {
throw new NullPointerException("key cannot be null");
}
final CountDownLatch latch = new CountDownLatch(1);
while (true) {
final CountDownLatch currentOwner = activeTasks.putIfAbsent(key, latch);
if (currentOwner == null) {
break;
} else {
currentOwner.await();
}
}
return () -> {
activeTasks.remove(key);
latch.countDown();
};
}
public interface Guard extends AutoCloseable {
#Override
void close();
}
}
You would use it as follows:
class RequestProcessor {
private final ObjectGuard<String> perObjectGuard = new ObjectGuard<>();
public String process(String objectId, String op) throws InterruptedException {
// Only one thread per object id can be present at any given time
try (ObjectGuard.Guard ignore = perObjectGuard.guardFor(objectId)) {
String result = ... // compute response
}
}
}
If two concurrent calls to process are received for the same object id, only one will be processed, the others wait their turn to process a request on that object.
An object which executes requests serially is known as Actor. The most widely known java actor library is named Akka. The most simple (one page) actor implementation is my SimpleActor.java.
Signalling like juancn does in his answer is not my strong suit, so I made an even cruder solution using one Semaphore for signalling combined with a request-counter.
There is one lock involved (subjectsLock) which synchronizes everything at one point in time. The lock is required to ensure there are no memory leaks: since there can be any number of subjects (a.k.a. object identifiers in your question), cleanup is essential. And cleanup requires knowing when something can be removed and that is difficult to determine without a lock that brings everything to one known state at a certain point in time.
The test in the main-method in the code shown below is a bit hard to read, but it serves as a starting point for a demonstration of how the code works internally. The main logic is in the methods executeRequest, addSubject and removeSubject. If those three methods do not make sense, another solution should be used.
Stress-testing will have to determine if this solution is fast enough: it depends on the number of requests (per second) and the amount of time it takes to complete an action. If there are many requests and the action is short/fast, the (synchronization) overhead from the lock could be to high.
// package so;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;
public class RequestQueue {
public static void main(String[] args) {
// Randomized test for "executeRequest" method below.
final int threadCount = 4;
ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);
try {
final int requestCount = 100;
final RequestQueue rq = new RequestQueue();
final Random random = new Random();
IntStream.range(0, requestCount).forEach(i -> threadPool.execute(new Runnable() {
#Override
public void run() {
try {
String subject = "" + (char) (((int)'A') + random.nextInt(threadCount));
rq.executeRequest(subject, new SleepAction(i, subject, 50 + random.nextInt(5)));
} catch (Exception e) {
e.printStackTrace();
}
}
}));
sleep(100); // give threads a chance to start executing.
while (true) {
sleep(200);
List<String> subjects = rq.getSubjects();
System.out.println("Subjects: " + subjects);
if (subjects.isEmpty()) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
private Map<String, QueueLock> subjects = new LinkedHashMap<>();
// a fair ReentrantLock is a little bit slower but ensures everybody gets their turn in orderly fashion.
private final ReentrantLock subjectsLock = new ReentrantLock(true);
private class QueueLock {
// a fair Semaphore ensures all requests are executed in the order they arrived.
final Semaphore turn = new Semaphore(1, true);
final AtomicInteger requests = new AtomicInteger(1);
public String toString() { return "request: " + requests.get(); }
}
/**
* Allow all requests for different subjects to execute in parallel,
* execute actions for the same subject one after another.
* Calling thread runs the action (possibly after waiting a bit when an action for a subject is already in progress).
*/
public String executeRequest(String subject, Runnable action) throws InterruptedException {
QueueLock qlock = addSubject(subject);
try {
int requestsForSubject = qlock.requests.get();
if (requestsForSubject > 1) {
System.out.println(action.toString() + " waiting for turn " + requestsForSubject);
}
qlock.turn.acquire();
if (requestsForSubject > 1) {
System.out.println(action.toString() + " taking turn " + qlock.requests.get());
}
action.run();
} catch (Exception e) {
e.printStackTrace();
} finally {
removeSubject(subject);
}
return timeSinceStart() + " " + subject;
}
private QueueLock addSubject(String s) {
QueueLock qlock = null;
subjectsLock.lock();
try {
qlock = subjects.get(s);
if (qlock == null) {
qlock = new QueueLock();
subjects.put(s, qlock);
} else {
qlock.requests.incrementAndGet();
}
} finally {
subjectsLock.unlock();
}
return qlock;
}
private boolean removeSubject(String s) {
boolean removed = false;
subjectsLock.lock();
try {
QueueLock qlock = subjects.get(s);
if (qlock.requests.decrementAndGet() == 0) {
subjects.remove(s);
removed = true;
} else {
qlock.turn.release();
}
} finally {
subjectsLock.unlock();
}
return removed;
}
public List<String> getSubjects() {
List<String> subjectsBeingProcessed = new ArrayList<>();
subjectsLock.lock();
try {
// maintains insertion order, see https://stackoverflow.com/a/18929873/3080094
subjectsBeingProcessed.addAll(subjects.keySet());
} finally {
subjectsLock.unlock();
}
return subjectsBeingProcessed;
}
public static class SleepAction implements Runnable {
final int requestNumber;
final long sleepTime;
final String subject;
public SleepAction(int requestNumber, String subject, long sleepTime) {
this.requestNumber = requestNumber;
this.sleepTime = sleepTime;
this.subject = subject;
}
#Override
public void run() {
System.out.println(toString() + " sleeping for " + sleepTime);
sleep(sleepTime);
System.out.println(toString() + " done");
}
public String toString() {return timeSinceStart() + " " + subject + " [" + Thread.currentThread().getName() + "] " + String.format("%03d",requestNumber); }
}
public static final long START_TIME = System.currentTimeMillis();
public static String timeSinceStart() {
return String.format("%05d", (System.currentTimeMillis() - START_TIME));
}
public static void sleep(long milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Due to the fact that in almost every question regarding the use of Thread.sleep it is mostly indicated to use it only in certain situations, I come to ask you if it is correct to use it in my case or if there is a better way to do it.
The operating system is Linux(Debian), in which a bash script is running that is detecting when a device (more specifically, a storage device) is inserted/removed, and then writes into a FIFO a string under the type "ADD {path-to-dev}" or "REM {path-to-dev}".
I created a small app in java which makes use of two threads. The first thread will call upon a read method that parses the String to the standard output, after which it will wait(). The second thread will check if the FIFO is empty or not and then, when it sees that a String has been inserted then it will call notify() so the other thread will print the String in there and so on. Inside the loop where it checks if the FIFO has data or not, I call Thread.sleep(1000), and I am unsure whether this is a good approach or not. I will present the code which handles all the action.
First, the class which has the methods of reading:
public class Detect {
private File file;
private BufferedReader read;
private volatile boolean readable;
private static String readFromFile;
public Detect() throws FileNotFoundException {
file = new File("/hardware_stuff/hardware_events");
read = new BufferedReader(new FileReader(file));
readable = true;
}
synchronized String readFromFifo() {
while (!readable) {
try {
wait();
} catch (InterruptedException ex) {
System.out.println("Interrupted during the wait for read.");
}
}
try {
while (read.ready()) {
readFromFile = read.readLine();
}
} catch (IOException ex) {
System.out.println("Error in reading from FIFO.");
}
readable = false;
notify();
return readFromFile;
}
synchronized void waitForFifo() {
while (readable) {
try {
wait();
} catch (InterruptedException ex) {
Logger.getLogger(Detect.class.getName()).log(Level.SEVERE, null, ex);
}
}
try {
while (!read.ready()) {
Thread.sleep(1000);
System.out.println("Sleeping due to lack of activity in FIFO in thread : " + Thread.currentThread().getName());
}
} catch (IOException | InterruptedException ex) {
Logger.getLogger(Detect.class.getName()).log(Level.SEVERE, null, ex);
}
readable = true;
notify();
}}
Next, the thread which will read from it.
public class ReadThread extends Thread {
Detect detect;
private boolean shouldBeRunning;
public ReadThread(Detect detect) {
this.detect = detect;
shouldBeRunning = true;
}
#Override
public void run() {
while (shouldBeRunning) {
String added = detect.readFromFifo();
System.out.println(added);
}
}
public void stopRunning() {
shouldBeRunning = false;
}}
Finally, the thread which will check if the FIFO is empty or not.
public class NotifyThread extends Thread {
Detect detect;
private boolean shouldBeRunning;
public NotifyThread(Detect detect) {
this.detect = detect;
shouldBeRunning = true;
}
#Override
public void run() {
while (shouldBeRunning) {
detect.waitForFifo();
}
}
public void stopRunning() {
shouldBeRunning = false;
}}
In main I just create the threads and start them.
Detect detect = new Detect();
NotifyThread nThread = new NotifyThread(detect);
ReadThread rThread = new ReadThread(detect);
nThread.start();
System.out.println("Started the notifier thread in : " + Thread.currentThread().getName());
rThread.start();
System.out.println("Started the reading thread in : " + Thread.currentThread().getName());
Is there any alternative to calling sleep or another approach I can take to replace the sleep with something else? I have already read other questions related to this topic and I am still uncertain/have not understood whether this sort of case is indicated for sleep or not.
UPDATE: As #james large said, there was no need to poll for ready. I was not aware that if there is no line, the readLine() will 'sleep' and there was no need to poll it after all. I removed the notifier thread, and I simply kept the ReadThread which will call the Detect readFromFifo() method and it all works good. #dumptruckman, thanks for the suggestion. Although it doesn't apply to my case, I didn't know of the WatchService and it was a good read, good stuff to know. #Nyamiou The Galeanthrope, the timer would have been useful, but as I already said, I only keep one thread to execute the same method and it works as intended.#Krzysztof Cichocki, thanks for pointing out there are issues. I was aware of that, otherwise I wouldn't have asked this question.
I have an external API I have to call that requires a validation token. The app calling the API will be threaded. Also, only 5 concurrent connections are allowed. I'm going to use a fixed thread pool for the connections, but I'm having an issue with figuring out how to handle an expired/invalid token. What I want to do is, when one thread encounters an expired token, prevent the other threads from acquiring the token until it has been refreshed. I'm thinking of using ReentrantLock to do this, but I'm not sure if my implementation is correct.
public static void main(String[] args){
for(int i = 0; i < 100; i++){
new Thread(new LockTest()).start();
}
}
public void testLock(String message) throws InterruptedException{
try{
getToken(message);
/*
* Use token here
*/
Thread.sleep(1000);
Random r = new Random();
int num = r.nextInt((25-0) + 1);
if(num == 1){ //testing only - exception thrown randomly.
throw new Exception("Token Expired!");
}
System.out.println("Message: " + message);
}catch(Exception e){
System.err.println(e.getMessage());
awaitTokenRefresh = true;
refreshToken();
}
}
private void refreshToken() throws InterruptedException {
lock.lock();
try{
System.out.println("Refreshing token...");
Thread.sleep(2000l);
System.out.println("Refreshed!");
awaitTokenRefresh = false;
awaitRefresh.signalAll();
}
finally{
lock.unlock();
}
}
//test use case for salesforce token
private void getToken(String message) throws InterruptedException {
lock.lock();
try{
while(awaitTokenRefresh){
System.out.println(message + " waiting for token refresh...");
awaitRefresh.await();
}
}
finally{
lock.unlock();
}
}
public void run(){
try {
System.out.println("Starting thread...");
testLock(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Just for testing, I've put in some sleeps to mimic work being done. The main thing I don't know about is, when thread A unlocks inside of getToken() thread B enters, but we don't know if the token is invalid yet. So B could actually be getting a bad token that A has to find. Is there a good way to handle this? Or is the idea of using locks completely wrong?
The first thing I notice is that your code is not properly synchronized. The exception handler in testLock() modifies shared variable awaitTokenRefresh at a point where that write is not ordered relative to other threads reading its value in getToken().
The main thing I don't know about is, when thread A unlocks inside of getToken() thread B enters, but we don't know if the token is invalid yet. So B could actually be getting a bad token that A has to find. Is there a good way to handle this? Or is the idea of using locks completely wrong?
I guess what you really want to avoid is unnecessary token refreshes when the current token becomes invalid. Exactly one thread should refresh it; the others should simply wait for the refresh and then continue about their business. The problem with your approach is that the threads have no good way to determine whether they are the first to detect the expiration, and so should take responsibility for refreshing. And indeed that makes sense, because the concept of which thread does anything first is not always well defined in a multithreaded application.
Whether you use locks vs. synchronization is an implementation detail of relatively minor consequence. The key is that you must have some shared state that tells threads whether the token they propose to refresh is in fact still current at all. I might implement it something like this:
public class MyClass {
private Object token = null;
private final Object tokenMonitor = new Object();
// ...
private Object getToken() {
synchronized (tokenMonitor) {
if (token == null) {
return refreshToken(null);
} else {
return token;
}
}
}
private Object refreshToken(Object oldToken) {
synchronized (tokenMonitor) {
if (token == oldToken) { // test reference equality
token = methodToPerformARefreshAndGenerateANewToken();
}
return token;
}
}
// ...
}
The idea there is when it tries to refresh the token, each thread specifies which token it is trying to refresh. A refresh is performed only if that is in fact the current token, and either way, the current token is returned.
You could use a ReentrantLock in place of my tokenMonitor, with locking and unlocking instead of synchronized blocks, but I much prefer plain synchronization when the scope is well contained, as in this case. Among other things, it's safer -- when you leave a synchronized block, you leave it; there is no possibility of failing to release the relevant monitor. The same cannot be said for lock objects.
This actually looks a problem that can be solved with versioning:
public class LockTest {
private int currentVersion = -1;
private Object token = null;
private synchronized int refreshToken(int requestorVersion) {
if (requestorVersion == currentVersion) {
try {
//do the actual refresh
Thread.sleep(1000);
token = new Object();
currentVersion++;
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
return currentVersion;
}
public VersionedToken takeToken() {
if (currentVersion == -1) {
refreshToken(-1);
}
return new VersionedToken(currentVersion);
}
public class VersionedToken {
private int version;
public VersionedToken(int version) {
this.version = version;
}
private void refresh() {
version = refreshToken(version);
}
private Object getToken() {
return token;
}
}
public static void main(String[] args) {
LockTest t = new LockTest();
for (int i = 0; i < 5; i++) {
new Thread(() -> {
VersionedToken vtoken = t.takeToken();
Object token = vtoken.getToken();
try {
//do something with the token
}catch (Exception ex) {
//if token went bad - just refresh it and continue to work with it afterwords
vtoken.refresh();
token = vtoken.getToken();
}
}).start();
}
}
}
Questions:
Why do I get a NoSuchElementException when trying to remove the last
element?
How can I fix that?
I have 3 classes (see below) that add/remove Integers to a LinkedList.
Everything works fine until the removing Threads get to the last element.
It seems like both threads try to remove it. The first one succeeds, the second one canĀ“t.
But I thought the synchronized-method/synchroniced-attribute + !sharedList.isEmpty() would handle that.
Class Producer:
This class is supposed to created random numbers, put them in the sharedList, write to console that it just added a number and stop once it gets interrupted. Only 1 thread of this class is expected.
import java.util.LinkedList;
public class Producer extends Thread
{
private LinkedList sharedList;
private String name;
public Producer(String name, LinkedList sharedList)
{
this.name = name;
this.sharedList = sharedList;
}
public void run()
{
while(!this.isInterrupted())
{
while(sharedList.size() < 100)
{
if(this.isInterrupted())
{
break;
} else
{
addElementToList();
}
}
}
}
private synchronized void addElementToList()
{
synchronized(sharedList)
{
sharedList.add((int)(Math.random()*100));
System.out.println("Thread " + this.name + ": " + sharedList.getLast() + " added");
}
try {
sleep(300);
} catch (InterruptedException e) {
this.interrupt();
}
}
}
Class Consumer: This class is supposed to remove the first element in the sharedList, if it exists. The execution should continue (after being interrupted) until sharedList is empty. Multiple (atleast 2) threads of this class are expected.
import java.util.LinkedList;
public class Consumer extends Thread
{
private String name;
private LinkedList sharedList;
public Consumer(String name, LinkedList sharedList)
{
this.name = name;
this.sharedList = sharedList;
}
public void run()
{
while(!this.isInterrupted())
{
while(!sharedList.isEmpty())
{
removeListElement();
}
}
}
private synchronized void removeListElement()
{
synchronized(sharedList)
{
int removedItem = (Integer) (sharedList.element());
sharedList.remove();
System.out.println("Thread " + this.name + ": " + removedItem + " removed");
}
try {
sleep(1000);
} catch (InterruptedException e) {
this.interrupt();
}
}
}
Class MainMethod: This class is supposed to start and interrupt the threads.
import java.util.LinkedList;
public class MainMethod
{
public static void main(String[] args) throws InterruptedException
{
LinkedList sharedList = new LinkedList();
Producer producer = new Producer("producer", sharedList);
producer.start();
Thread.sleep(1000);
Consumer consumer1 = new Consumer("consumer1", sharedList);
Consumer consumer2 = new Consumer("consumer2", sharedList);
consumer1.start();
consumer2.start();
Thread.sleep(10000);
producer.interrupt();
consumer1.interrupt();
consumer2.interrupt();
}
}
Exception: This is the exact exception I get.
Exception in thread "Thread-2" java.util.NoSuchElementException at
java.util.LinkedList.getFirst(LinkedList.java:126) at
java.util.LinkedList.element(LinkedList.java:476) at
Consumer.removeListElement(Consumer.java:29) at
Consumer.run(Consumer.java:20)
Your exception is rather simple to explain. In
while(!sharedList.isEmpty())
{
removeListElement();
}
sharedList.isEmpty() happens outside of synchronization and so one consumer can still see a list as empty while another consumer has already taken the last element.
The consumer that wrongfully believed it is empty will not try to remove an element that is no longer there which leads to your crash.
If you want to make it threadsafe using a LinkedList you'll have to do every read / write operation atomic. E.g.
while(!this.isInterrupted())
{
if (!removeListElementIfPossible())
{
break;
}
}
and
// method does not need to be synchronized - no thread besides this one is
// accessing it. Other threads have their "own" method. Would make a difference
// if this method was static, i.e. shared between threads.
private boolean removeListElementIfPossible()
{
synchronized(sharedList)
{
// within synchronized so we can be sure that checking emptyness + removal happens atomic
if (!sharedList.isEmpty())
{
int removedItem = (Integer) (sharedList.element());
sharedList.remove();
System.out.println("Thread " + this.name + ": " + removedItem + " removed");
} else {
// unable to remove an element because list was empty
return false;
}
}
try {
sleep(1000);
} catch (InterruptedException e) {
this.interrupt();
}
// an element was removed
return true;
}
The same problem exists within your producers. But they would just create a 110th element or something like that.
A good solution to your problem would be using a BlockingQueue. See the documentation for an example. The queue does all the blocking & synchronization for you so your code does not have to worry.
Edit: regarding 2 while loops: You don't have to use 2 loops, 1 loop loops enough but you'll run into another problem: consumers may see the queue as empty before the producers have filled it. So you either have to make sure that there is something in the queue before it can be consumed or you'll have to stop threads manually in other ways. You thread.sleep(1000) after starting the producer should be rather safe but threads are not guaranteed to be running even after 1 second. Use e.g. a CountDownLatch to make it actually safe.
I am wondering why you are not using the already existing classes that Java offers. I rewrote your program using those, and it becomes much shorter and easier to read. In addition the lack of synchronized, which blocks all threads except for the one who gets the lock (and you even do double synchronization), allows the program to actually run in parallel.
Here is the code:
Producer:
public class Producer implements Runnable {
protected final String name;
protected final LinkedBlockingQueue<Integer> sharedList;
protected final Random random = new Random();
public Producer(final String name, final LinkedBlockingQueue<Integer> sharedList) {
this.name = name;
this.sharedList = sharedList;
}
public void run() {
try {
while (Thread.interrupted() == false) {
final int number = random.nextInt(100);
sharedList.put(number);
System.out.println("Thread " + this.name + ": " + number);
Thread.sleep(100);
}
} catch (InterruptedException e) {
}
}
}
Consumer:
public class Consumer implements Runnable {
protected final String name;
protected final LinkedBlockingQueue<Integer> sharedList;
public Consumer(final String name, final LinkedBlockingQueue<Integer> sharedList) {
this.name = name;
this.sharedList = sharedList;
}
public void run() {
try {
while (Thread.interrupted() == false) {
final int number = sharedList.take();
System.out.println("Thread " + name + ": " + number + " taken.");
Thread.sleep(100);
}
} catch (InterruptedException e) {
}
}
}
Main:
public static void main(String[] args) throws InterruptedException {
final LinkedBlockingQueue<Integer> sharedList = new LinkedBlockingQueue<>(100);
final ExecutorService executor = Executors.newFixedThreadPool(4);
executor.execute(new Producer("producer", sharedList));
Thread.sleep(1000);
executor.execute(new Consumer("consumer1", sharedList));
executor.execute(new Consumer("consumer2", sharedList));
Thread.sleep(1000);
executor.shutdownNow();
}
There are several differences:
Since I use a concurrent list, I do not have to care (much) about synchronization, the list does that internally.
As this list uses atomic locking instead of true blocking via synchronized it will scale much better the more threads are used.
I do set the limit of the blocking queue to 100, so even while there is no check in the producer, there will never be more than 100 elements in the list, as put will block if the limit is reached.
I use random.nextInt(100) which is a convenience function for what you used and will produce a lot less typos as the usage is much clearer.
Producer and Consumer are both Runnables, as this is the preferred way for threading in Java. This allows to later on wrap any form of thread around them for execution, not just the primitive Thread class.
Instead of the Thread, I use an ExecutorService which allows easier control over multiple threads. Thread creation, scheduling and other handling is done internally, so all I need to do is to choose the most appropriate ExecutorService and call shutdownNow() when I am done.
Also note that there is no need to throw an InterruptedException into the void. If the consumer/producer is interrupted, that is a signal to stop execution gracefully as soon as possible. Unless I need to inform others "behind" that thread, there is no need to throw that Exception again (although no harm is done either).
I use the keyword final to note elements that won't change later on. For once this is a hint for the compiler that allows some optimizations, it as well helps me to prevent an accidental change of a variable that is not supposed to change. A lot of problems can be prevented by not allowing variables to change in a threaded environment, as thread-issues almost always require something to be read and written at the same time. Such things cannot happen if you cannot write.
Spending some time to search through the Java library for the class that fits your problem the best usually solves a lot of trouble and reduces the size of the code a lot.
Try to switch places of
while(!sharedList.isEmpty())
and
synchronized(sharedList)
I don't think you need synchronized on removeListElement().