I've been working on writing a simple program in an attempt to understand Java's multithreading feature in combination with Listeners to use as notifying agent at Thread's closure. Below are the Interface/classes that are in use (mostly grabbed from the web and tweaked a bit):
public interface ThreadCompleteListener {
void notifyOfThreadComplete(final NotifyingThread thread);
}
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
public abstract class NotifyingThread extends Thread {
private final Set<ThreadCompleteListener> listeners = new CopyOnWriteArraySet<ThreadCompleteListener>();
public final void addListener(final ThreadCompleteListener listener) {
listeners.add(listener);
}
public final void removeListener(final ThreadCompleteListener listener) {
listeners.remove(listener);
}
private final void notifyListeners() {
for (ThreadCompleteListener listener : listeners) {
listener.notifyOfThreadComplete(this);
}
}
@Override
public final void run() {
try {
doRun();
} finally {
notifyListeners();
}
}
public abstract void doRun();
}
Version 1 of Class InvokeThread
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class InvokeThread implements ThreadCompleteListener{
List<String> synList = Collections.synchronizedList(new ArrayList<String>());
int threadNotifyCount = 0;
String threadList = "";
public static void main(String[] args) {
InvokeThread ma_0 = new InvokeThread();
ma_0.execute(args);
}
@Override
public void notifyOfThreadComplete(NotifyingThread thread) {
String _temp = threadList.substring(0, threadList.length()-1);
threadNotifyCount ;
if(threadNotifyCount == _temp.split(",").length) {
Collections.sort(synList);
System.out.println(thread.getName() ": " synList);
}
}
public String execute(String[] args) {
// Start the Thread
NotifyingThread thread1 = new NotifyingThread() {
@Override
public void doRun() {
synchronized (this) {
// synList.addAll(Arrays.asList("zebra", "cow", "rabbit"));
threadList = this.getName() "," threadList;
synList.addAll(Arrays.asList(args[0].split(",")));
}
}
};
thread1.addListener(this);
thread1.start();
NotifyingThread thread2 = new NotifyingThread() {
@Override
public void doRun() {
synchronized (this) {
threadList = this.getName() "," threadList;
synList.addAll(Arrays.asList(args[idx].split(",")));
}
}
};
thread2.addListener(this);
thread2.start();
return "";
}
}
Version 2 of Class InvokeThread
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class InvokeThread implements ThreadCompleteListener{
List<String> synList = Collections.synchronizedList(new ArrayList<String>());
int threadNotifyCount = 0;
String threadList = "";
public static void main(String[] args) {
InvokeThread ma_0 = new InvokeThread();
ma_0.execute(args);
}
@Override
public void notifyOfThreadComplete(NotifyingThread thread) {
String _temp = threadList.substring(0, threadList.length()-1);
threadNotifyCount ;
if(threadNotifyCount == _temp.split(",").length) {
Collections.sort(synList);
System.out.println(thread.getName() ": " synList);
}
}
public String execute(String[] args) {
int argsCount = args.length;
for(int idx=0;idx<argsCount;idx ) {
NotifyingThread thread = new NotifyingThread() {
@Override
public void doRun() {
synchronized (this) {
threadList = this.getName() "," threadList;
synList.addAll(Arrays.asList(args[1].split(",")));
}
}
};
thread.addListener(this);
thread.start();
}
return "";
}
}
Input arguments:
"zebra,cow,rabbit"
"giraffe,camel,buffalo"
Given above two versions of a given class InvokeThread. The first version does print a sorted list of String objects, consistently. The second version occasionally prints nothing. Please, help me understand the occurrence. TIA.
EDIT - 1 (after changing the code to fix the bug that Solomon reported on comments section):
Version 2 of NotifyingThread:
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
public abstract class NotifyingThread extends Thread {
private final Set<ThreadCompleteListener> listeners = new CopyOnWriteArraySet<ThreadCompleteListener>();
public final void addListener(final ThreadCompleteListener listener) {
listeners.add(listener);
}
public final void removeListener(final ThreadCompleteListener listener) {
listeners.remove(listener);
}
private final void notifyListeners() {
for (ThreadCompleteListener listener : listeners) {
listener.notifyOfThreadComplete(this);
}
}
private int idx;
public NotifyingThread(int index) {
this.idx = index;
}
@Override
public final void run() {
try {
doRun(idx);
} finally {
notifyListeners();
}
}
public abstract void doRun(int idx);
}
Version 2.1 of InvokeThread:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class InvokeThread implements ThreadCompleteListener{
List<String> synList = Collections.synchronizedList(new ArrayList<String>());
int threadNotifyCount = 0;
String threadList = "";
public static void main(String[] args) {
InvokeThread ma_0 = new InvokeThread();
ma_0.execute(args);
}
@Override
public void notifyOfThreadComplete(NotifyingThread thread) {
String _temp = threadList.substring(0, threadList.length()-1);
threadNotifyCount ;
if(threadNotifyCount == _temp.split(",").length) {
Collections.sort(synList);
System.out.println(thread.getName() ": " synList);
}
}
public String execute(String[] args) {
int argsCount = args.length;
for(int idx=0;idx<argsCount;idx ) {
NotifyingThread thread = new NotifyingThread(idx) {
@Override
public void doRun(int idx) {
synchronized (this) {
// synList.addAll(Arrays.asList("giraffe", "camel", "buffalo"));
threadList = this.getName() "," threadList;
synList.addAll(Arrays.asList(args[idx].split(",")));
}
}
};
thread.addListener(this);
thread.start();
}
return "";
}
}
The fixture does fix the original problem reported which was v2 of this class not printing list occasionally. However, I would like to keep the question open to request clarity on Solomon's remark on no-synchronization.
CodePudding user response:
Following changes (as a result of Solomon's prompt) offered fixture:
Version 2 of NotifyingThread:
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
public abstract class NotifyingThread extends Thread {
private final Set<ThreadCompleteListener> listeners = new CopyOnWriteArraySet<ThreadCompleteListener>();
public final void addListener(final ThreadCompleteListener listener) {
listeners.add(listener);
}
public final void removeListener(final ThreadCompleteListener listener) {
listeners.remove(listener);
}
private final void notifyListeners() {
for (ThreadCompleteListener listener : listeners) {
listener.notifyOfThreadComplete(this);
}
}
private int idx;
public NotifyingThread(int index) {
this.idx = index;
}
@Override
public final void run() {
try {
doRun(idx);
} finally {
notifyListeners();
}
}
public abstract void doRun(int idx);
}
Version 2.1 of InvokeThread:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class InvokeThread implements ThreadCompleteListener{
List<String> synList = Collections.synchronizedList(new ArrayList<String>());
int threadNotifyCount = 0;
String threadList = "";
public static void main(String[] args) {
InvokeThread ma_0 = new InvokeThread();
ma_0.execute(args);
}
@Override
public void notifyOfThreadComplete(NotifyingThread thread) {
String _temp = threadList.substring(0, threadList.length()-1);
threadNotifyCount ;
if(threadNotifyCount == _temp.split(",").length) {
Collections.sort(synList);
System.out.println(thread.getName() ": " synList);
}
}
public String execute(String[] args) {
int argsCount = args.length;
for(int idx=0;idx<argsCount;idx ) {
NotifyingThread thread = new NotifyingThread(idx) {
@Override
public void doRun(int idx) {
synchronized (this) {
// synList.addAll(Arrays.asList("giraffe", "camel", "buffalo"));
threadList = this.getName() "," threadList;
synList.addAll(Arrays.asList(args[idx].split(",")));
}
}
};
thread.addListener(this);
thread.start();
}
return "";
}
}