Is the lock being done correctly - java

I am reading a UDP feed then decoding it and writing to MSMQ(Message Queuing).
I create a new thread that calls UDPReader. In turn UDPReader creates a threadpool and calls class ipaddrConnection. Run inside ipaddrConnection contains a while loop that continuously reads packets from the Multicast socket and pushes it to class parseUDP. From parseUDP it is decoded and finally pushed to the class that writes to MSMQ. I believe I am not locking the threads properly when it comes to the while loop in ipaddrConnection because threads are attempting to write to the same memory location in MSMQ. I thought that by placing my lock in the while loop, each thread in the pool would have its own time in the "Critical Section" 1.receive a packet then 2.decode and write to MSMQ. I am still learning concurrency and looking for some help. I have provided a crash dump file that I don't understand how to properly read and my UDPReader and ipaddrConnection classes. parseUDP calls a class to decode the packet and that class calls a MSMQ class to write to memory. All of which are in my Critical Section.
class UDPReader implements Runnable
{
private final String ip, socket, queue, threadName;
private final JTextArea screen;
UDPReader(String ip, String socket, String queue, String threadName, JTextArea screen)
{
this.ip = ip;
this.socket = socket;
this.queue = queue;
this.threadName = threadName;
this.screen = screen;
}
public void run()
{
screen.append("Thread " + threadName + " running\n\n");
ExecutorService executor = Executors.newFixedThreadPool(5);
Runnable reader = new ipaddrConnection(ip, socket, queue);
executor.execute(reader);
}
}
public final class ipaddrConnection implements Runnable
{
private final ReentrantLock lock = new ReentrantLock();
byte[] bytes = new byte[(int)100000];
InetAddress group;
MulticastSocket s;
DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
private String queue;
public ipaddrConnection(String ip, String socket, String queue) {
try {
this.s = new MulticastSocket(Integer.parseInt(socket));
this.group = InetAddress.getByName(ip);
this.queue = queue;
} catch (IOException ex) {
Logger.getLogger(ipaddrConnection.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void run() {
try {
parseUDP p = new parseUDP(queue);
s.joinGroup(group);
s.setSoTimeout(95000);
try{
while(true){
lock.lock();
s.receive(packet);
p.parseUDP(packet.getData());
}
}finally {
lock.unlock();
}
} catch (SocketException ex) {
Logger.getLogger(ipaddrConnection.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(ipaddrConnection.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Crash Report
https://drive.google.com/file/d/0B4GWNCU6_CBlM2tJNGJqNzRVazg/view?usp=sharing

In your code, your locks don't do anything useful.
Each thread has its own lock, so there can be more than one thread using the queue at a time (because Thread 1 locked Lock 1, and Thread 2 locked Lock 2, and there's nothing stopping them using the queue at the same time).
If you make the lock field static in your code, then the threads will all use the same lock.
You might still have problems, because threads never release the lock (unless they encounter an exception) so only one thread will be allowed to do work:
try{
while(true){
lock.lock();
s.receive(packet);
p.parseUDP(packet.getData());
}
}finally {
lock.unlock();
}
Notice how the only way the thread can unlock the lock is if there's an exception?
You might have wanted something more like this:
while(true) {
s.receive(packet);
try {
lock.lock();
s.parseUDP(packet.getData());
} finally {
lock.unlock();
}
}
- with this structure, threads will only hold the lock while they are parsing the packets, not while they are receiving packets. (I don't know whether this is what you actually want)

ExecutorService executor = Executors.newFixedThreadPool(5);
Runnable reader = new ipaddrConnection(ip, socket, queue);
executor.execute(reader);
This code is, in effect, single threaded since although the pool has five threads, you are using up only one.

Having UDPReader implement Runnable and it's run() implementation is at the very least not idiomatic.
As mentioned by immibis your lock objects are not shared between the threads and they don't provide the protection you are looking for.
You unlock only when you exit while (true) { ... } which is to say never. With this in mind you may want to consider something like:
public class UDPReader {
...
UDPReader(String ip, String socket, String queue, String threadName, JTextArea screen, numberOfThreads) {
...
this.numberOfThreads = numberOfThreads;
this.lock = new ReentrantLock();
}
public void run() {
ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
for (int i = 0; i < numberOfThreads; i++){
executor.execute(new ipaddrConnection(ip, socket, queue, lock));
}
}
}
public final class ipaddrConnection implements Runnable {
private lock ;
...
public ipaddrConnection(String ip, String socket, String queue, ReentrantLock lock) {
...
this.lock = lock;
}
#Override
public void run() {
...
while (true) {
try {
lock.lock();
s.receive(packet);
p.parseUDP(packet.getData());
} finally {
lock.unlock();
}
}
....
}
}
}

Related

NullPointerException for PrintWriter thats initialized in the run method of a thread

im making a networked game that has a server which creates a clientHandler thread every time a client joins. I want to ask the first client that joined if it wants to start the game every time a new client joins, giving it the current number of players connected. Writting through the clientHandlers printwritter gives a nullPointerException, even though ive started the thread before doing this. what could be the problem?
Here is the server code:
`public class Server implements Runnable{
private ArrayList<ClientHandler> handlers = new ArrayList<>();
private ArrayList<Player> players = new ArrayList<>();
private Game game;
private boolean start;
public static void main(String[] args) {
Server server = new Server();
Thread s = new Thread(server);
s.start();
}
public void login(String name){
//todo
for (ClientHandler c : handlers){
if (c.getName().equals(name)){
alreadyTaken(name);//todo
}
else{
players.add(new HumanPlayer(name,c));//todo
}
}
}
public void setStart(){
start = true;
}
private void alreadyTaken(String name) {
}
public void setTurn(ServerHandler sh){
//todo
}
public void updateView(){
}
public String hello() {
return "Hello"; //?
}
public void place(String s){
}
#Override
public void run() {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(1800);
} catch (IOException e) {
throw new RuntimeException(e);
}
System.out.println("----Server----");
while (!serverSocket.isClosed()) {
try {
Socket socket = serverSocket.accept();
ClientHandler handler = new ClientHandler(socket,handlers,this);
handlers.add(handler);
Thread h = new Thread(handler);
h.start();
System.out.println("A new client has connected");
System.out.println(handlers.get(0));
handlers.get(0).out.println("START? "+ handlers.size());
if (start){
System.out.println("start request works");
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
`
And here's the client handler code:
`public class ClientHandler implements Runnable{
private Socket socket;
private ArrayList<ClientHandler> handlers;
private Server server;
public PrintWriter out;
private BufferedReader in;
private String name;
public ClientHandler(Socket socket, ArrayList<ClientHandler> handlers, Server server){
this.socket = socket;
this.handlers = handlers;
this.server = server;
}
public void broadcastMessage(String msg){
System.out.println("Broadcasting");
for (ClientHandler s : this.handlers){
s.out.println("Player: " + msg);
}
}
public static String removePrefix(String s, String prefix)
{
if (s != null && s.startsWith(prefix)) {
return s.split(prefix, 2)[1];
}
return s;
}
public String getName(){
return name;
}
#Override
public void run() {
try {
out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
new Thread(() -> {
while(socket.isConnected()){
String msg;
try {
msg = in.readLine();
while(msg!=null){
switch (msg.split(" ")[0]){
case "LOGIN":
name = removePrefix(msg,"LOGIN ");
server.login(name);//todo
break;
case "HELLO":
server.hello();//todo
break;
case "PLACE":
server.place(removePrefix(msg,"PLACE "));
break;
case "QUIT":
//todo
break;
case "STOP":
//todo
break;
case "START":
server.setStart();
default:
broadcastMessage(msg);
break;
}
msg = in.readLine();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}`
I tried making a method in the client handler class which does the same thing. The server would just call that instead of writting directing through the PrintWriter, but i got the same error.
Starting a thread does not mean it is guaranteed to actually finish executing the first statement in its run() method before start() returns. In fact,
Usually it won't - starting a thread takes some time, and start() returns as soon as it can.
A JVM that runs a few statements in the thread you just started before start() returns is 'correct' - that is fine. A JVM that doesn't is also fine. Generally you don't want threads, because nothing is predictable anymore. At the very least you want to keep 'inter-thread comms' down to a minimum. Anytime a single field is used from more than one thread, things get very tricky.
What you need is synchronized or other tools to insert predictability in this code.
First, fix a bug
Your ClientHandler's run() code starts another thread for no reason. Take all that out, your run() method in ClientHandler should set up out and in and then immediately do while (socket.isConnected())
Synchronizing
At the very basic level, make a locker object and use notify/wait:
private final Object lock = new Object();
#Override public void run() {
try {
synchronized (lock) {
out = ...;
in = ...;
lock.notifyAll();
}
while (socket.isConnected()) { ... }
out definitely cannot be public here, you can't refer to a stream from multiple threads and expect things to work out!
Just 'fixing' your code involves then using something like:
public OutputStream getOutputStream() {
synchronized (lock) {
while (out == null) {
lock.wait();
}
}
return out;
}
Which will ensure that any thread that wants the out will wait for the other thread to get far enough, but, really, this is just setting you up for another 20 threading problems down the line. Instead, you want one object responsibile for all communication (both outgoing and incoming), and a concurrency-capable queue (there are various collections in the java.util.concurrent package good for this). Then:
Any other threads that want to just send data dump their message in the queue.
You have either 1 thread doing all comms, or 2 (one doing incoming, and one doing outgoing), both dedicated. The outgoing one just loops forever, grabbing objects from the queue and sending them.
If a thread wants to send a message and wait for the response, you need to use .wait() or nicer API from e.g. java.util.concurrent, or, use callback hell - you pass a closure with the code to run once the result is received.

Signal thread error to main thread

I have a thread in Java that is connecting to a socket and sending information to another thread, which is processing that information.
Now, if the "producer" thread fails for any reason, I want the whole program to stop, so some sort of notification must happen.
Here's my program (very simplified):
public class Main {
private Queue<String> q = new ConcurrentLinkedQueue();
public static void main(String[] args) throws IOException {
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
// Catch any error in the producer side, then stop both consumer and producer, and do some extra work to notify me that there's an error...
}
}
Main code just creates a shared queue, and starts both producer and consumer. So far, I guess it's ok? Now the Producer code is like this:
public class Producer implements Runnable {
private Queue<String> q;
public Producer(Queue<String> q) {
this.q = q;
}
public void run() {
try {
connectToSocket();
while(true) {
String data = readFromSocket()
q.offer(data);
}
} catch (Exception e) {
// Something really bad happened, notify the parent thread so he stops the program...
}
}
}
Producer connects to socket, reads and sends to queue the string data... The consumer:
public class Consumer implements Runnable {
private Queue<String> q;
public Consumer(Queue<String> q) {
this.q = q;
}
public void run() {
while(true) {
String dataFromSocket = q.poll();
saveData(dataFromSocket);
}
}
}
My code does a lot more than that, but I think it's now self-explanatory what I'm trying to do. I've read about wait() and notify() but I think that wouldn't work, because I don't want to wait my thread for an exception, I want to deal with it in a better way. What are the alternatives?
In general, does my code look reasonable? Would using ExecutorService help here at all?
Thanks a lot!
you can use Thread's UncaughtExceptionHandler
Thread.setDefaultExceptionHandler(
new UncaughtExceptionHandler() {
public void unchaughtException(Thread th, Throwable exception) {
System.out.println("Exception from Thread" + th + ". Exception:" + exception);
}
});
Java docs
http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.UncaughtExceptionHandler.html
The simplest solution given your current code would be to wait for the producer thread to finish and then interrupt the consumer:
Thread producerThread = new Thread(new Producer(q));
producerThread.start();
Thread consumerThread = new Thread(new Consumer(q));
consumerThread.start();
try {
producerThread.join();
} finally {
consumerThread.interrupt();
}
As you mention, an executor would give you a more general purpose way to shut down everything when you need to exit (for example, when a interrupted in the terminal with ctrl-c).
ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
Producer producer = new Producer(q);
Consumer consumer = new Consumer(q);
executor.submit(producer::run);
executor.submit(consumer::run);
Runtime.getRuntime().addShutdownHook(new Thread(executor::shutdownNow));
Note that your cleanup would have to be more comprehensive than just shutting down the executor. You would have to close the socket beforehand to allow the threads to be interrupted.
Here is a more complete example that handles shutdown from both sides. You can test it by starting a test server with nc -l 1234. Killing either process (nc or the java client) will result in a clean exit of the other.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
public class Main {
private ExecutorService executor;
private Socket socket;
private AtomicBoolean running = new AtomicBoolean(true);
public static void main(String[] args) throws IOException {
Main main = new Main();
main.run();
}
private Main() throws IOException {
executor = Executors.newCachedThreadPool();
socket = new Socket("localhost", 1234);
}
private void run() throws IOException {
BlockingQueue<String> q = new SynchronousQueue<>();
Producer producer = new Producer(socket, q);
Consumer consumer = new Consumer(q);
// Start the producer. When it ends call stop
CompletableFuture.runAsync(producer, executor).whenComplete((status, ex) -> stop());
// Start the consumer.
CompletableFuture.runAsync(consumer, executor);
// Add a shutdown hook to stop everything on break
Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
}
private void stop() {
if (running.compareAndSet(true, false)) { // only once
// Close the socket to unblock the producer
try {
socket.close();
} catch (IOException e) {
// ignore
}
// Interrupt tasks
executor.shutdownNow();
try {
// Give tasks some time to clean up
executor.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// ignore
}
}
}
static class Producer implements Runnable {
private BufferedReader in;
private BlockingQueue<String> q;
public Producer(Socket socket, BlockingQueue<String> q) throws IOException {
this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
this.q = q;
}
#Override
public void run() {
try {
while (true) {
String data = in.readLine();
if (data == null) {
break;
}
q.put(data);
}
} catch (InterruptedException | IOException e) {
// Fall through
}
System.err.println("Producer done");
}
}
static class Consumer implements Runnable {
private BlockingQueue<String> q;
public Consumer(BlockingQueue<String> q) {
this.q = q;
}
#Override
public void run() {
try {
while (true) {
System.out.println(q.take());
}
} catch (InterruptedException e) {
// done
}
System.err.println("Client done");
}
}
}
Start consumer thread as 'daemon' thread
Mark the consumer thread as 'daemon' and let the main thread end too:
From the Java API doc for Thread.setDaemon(boolean):
Marks this thread as either a daemon thread or a user thread. The Java Virtual Machine exits when the only threads running are all daemon threads.
public class Main {
private Queue<String> q = new ConcurrentLinkedQueue();
public static void main(String[] args) throws IOException {
Thread producerThread = new Thread(new Producer(q));
// producerThread.setDefaultUncaughtExceptionHandler(...);
producerThread.start();
Thread consumerThread = new Thread(new Consumer(q));
consumerThread.setDeamon(true);
consumerThread.start();
}
}
This way, your application automatically stops, when the main thread and the producer-thread have terminated (sucessfully or by exception).
You could combine this with the UncaughtExceptionHandler as #Manish suggested, if the main thread needs to know about the producerThread failing...
How about volatile?
public class Main {
volatile boolean isStopMain = false;
private Queue<String> q = new ConcurrentLinkedQueue();
public static void main(String[] args) throws IOException {
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
// Catch any error in the producer side, then stop both consumer and producer, and do some extra work to notify me that there's an error...
while (true) {
if(isStopMain){
System.exit(0); //or other operation to stop the main thread.
}
}
}
}
And In Producer:
public class Producer implements Runnable {
private Queue<String> q;
public Producer(Queue<String> q) {
this.q = q;
}
public void run() {
try {
connectToSocket();
while(true) {
String data = readFromSocket()
q.offer(data);
}
} catch (Exception e) {
// Something really bad happened, notify the parent thread so he stops the program...
Main.isStopMain = true;
}
}
}
And I wonder if you are trying to kill the parent thread in child thread? If yes, here is something you may need to know:How do I terminate parent thread from child?

Can't stop ExecutorService in java

I have a problem with ExecutorService. I have a button in GUI that calls Runnable class that contains ExecutorService. I tried everything to stop ExecutorService (or main thread) but I didn't find a way to end it. Here is my code. Please post your answers and advises. Best regards.
public void actionPerformed(ActionEvent e) {
final FindGateWaysAndIps scanner = new FindGateWaysAndIps();
if (e.getActionCommand()=="Start Scan"){
scanner.start();
}
if (e.getActionCommand()=="Stop Scan"){
scanner.interrupt();
scanner.stopScans();
}
}
Class "FindGateWaysAndIps"
String ip = "192.168.";
String sql =" ";
static volatile boolean stop = false;
PingResult AllResaults = new PingResult();
int [] AllGateWays = new int [256];
final int NUM_THREADS = Runtime.getRuntime().availableProcessors();
ExecutorService exec = Executors.newFixedThreadPool(NUM_THREADS*5);
public void run() {
stop=true;
while(stop){
for (;GateWayKey<=GateWayKeyStop;GateWayKey++){
if (!stop){
exec.shutdownNow();
Thread.currentThread().interrupt();
break;
}
ip="192.168."+GateWayKey+".1";
AllSQLs.add(exec.submit((new PingTask(ip,GateWayKey,true))));
}
if (!stop) {
exec.shutdownNow();
Thread.currentThread().interrupt();
break;
}
AllGateWays=GetVectorData.GiveMeGateWays();
for (int j=0; j<= AllGateWays.length;j++){
System.out.println("stop je: "+stop);
if (!stop){
exec.shutdownNow();
Thread.currentThread().interrupt();
break;
}
removeDuplicateinVectors();
//System.out.println("Sada je j"+j);
for (;SubNetKey<=SubNetKeyStop;SubNetKey++){
if (!stop){
exec.shutdownNow();
Thread.currentThread().interrupt();
break;
}
ip="192.168."+AllGateWays[j]+"."+SubNetKey;
AllSQLs.add (exec.submit((new PingTask(ip,AllGateWays[j],false))));
}
// Process the result here (this is where you insert into the DB)
//WriteAllDataIntoDataBase();
}
exec.shutdown();
//WriteAllDataIntoDataBase();
}
public void stopScans(){
exec.shutdownNow();
stop=false;
}
Sorry here is PingTask class
public class PingTask implements Callable <String> {
String ips;
String sql;
PingResult PassDataToExternalClass = new PingResult();
//FindGateWaysAndIps DataProccesor = new FindGateWaysAndIps();
int GateWay;
ScanFrame MonitorData = new ScanFrame();
boolean GateWayORSubNet;
int [] AllGateWays = new int [256];
int i=0;
public int[] GiveMeGateWays(){
return AllGateWays;
}
public PingTask (){
}
public PingTask (String ip, int GateWayKey, boolean GateWayORSubNets){
ips=ip;
GateWay=GateWayKey;
GateWayORSubNet=GateWayORSubNets;
}
public String call(){
InetAddress address;
try {
address = InetAddress.getByName(ips);//ako nade gateway neka skoci u petlju u kojoj nade IP adrese pripadajuceg gatewaya
System.out.println("PINGAM: "+ips);
try {
if (address.isReachable(2000)) { //pinga gatewaya s 1000ms (jeli je moguce ovo smanjiti da se ubrza proces)?
System.out.println("Nasa sam IP: "+ips);
AllGateWays[i]=GateWay;
i++;
MonitorData.WriteMonitorData(ips,address.getHostName().toString(),"2000","da");
if (GateWayORSubNet){
sql="REPLACE INTO `gateways` (`ID_GATEWAY` , `GATEWAY_IP` , `GATEWAY_NAME`) VALUES ('"+GateWay+"', '"+ips+"', '"+address.getHostName().toString()+"');";
return sql;
}
else{
sql="REPLACE INTO `subnets` (`IP` , `COMPUTER_NAME` , `GATEWAY_KEY`) VALUES ('"+ips+"', '"+address.getHostName().toString()+"', '"+GateWay+"');";
return sql;
}
} else {
return ";";
}
} catch (IOException e) {
return ";";
}
} catch (UnknownHostException e) {
return ";";
}
}
}
Effectively, in order to get threads stopped, each thread within a pooler inialized by ExecutorService must defined a treatment when this one get interrupted.
This is why daemon starting by:
while(true){
}
isn't suitable and is one of the cause of the impossibility of shutdowning the thread pooler.
Prefer for instance:
while(!Thread.currentThread.isInterrupted){
}
//do here what to do in order to exit and clean safely your job and used resources like open filed.
But even with this, you make wonder what it may not work ......
Avoid to swallow InterruptedException!:
catch(InterruptedException e){
//do nothing
}
Indeed, the interrupted flag is cleared when exception is catched ! So don't forget to set it to true by reinpterrupting the thread:
catch(InterruptedException e){
Thread.currentThread.interrupt();
}
For a more detailed explanation, open this link:
http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html
I guess your PingTask is making URL Connections and connect() call is non interruptible call.
ExecutorService#shutdownNow() offers a way of immediate shutdown by interrupting threads but since these threads can not be interrupted it provides not additional benefit.
It only provides benefit when thread has defined its interruption policy and it performs interruptible operations.
Your problem may be that address.isReachable(...) is not interruptible. Interrupting the thread, like #Mik378 mentioned, sets the interrupt bit on the thread and causes some methods (Thread.sleep(), Object.wait(), and others) to throw InterruptedException. The InetAddress.isReachable(...) will not get interrupted unfortunately.
If you are trying to have your print threads finish immediately so the application can exit, you could make them daemon threads. See here:
Making Callable Threads as Daemon

Facing issue in java MultiThreading

Im facing one problem in streaming data capture for reading the broadcast data during multithreading, pls help or suggest,
Actually there is one class which is reading data from one of the udp socket. Another class accepts the tcp connection from every client request, creates a thread for every client and request the same udp class for data. The thing is working with 1st thread which gets created. But when i request with another client from another pc/ip the packets get losted to the 2nd client/thread
I have made a workaround by creating a list where im storing the Threads outputstream object
and looping it to send the data to all the client. But this is just temporary as it ll delay the packets if clients/connections gets increased.
code for reading UDP Data
public class EventNotifier
{
private InterestingEvent ie;
public DatagramSocket clientSocket;
public String[] split_str;
byte[] receiveData;
HashMap<String, String> secMap = new HashMap<String, String>();
public EventNotifier(InterestingEvent event)
{
ie = event;
clientSocket = new DatagramSocket(9050);
receiveData = new byte[500];
}
public String getDataFeed(String client_id)
{
try
{
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
clientSocket.receive(receivePacket);
String s = new String(receivePacket.getData());
String split_str = s.split(",");
if(secMap.containsValue(split_str[0]))
return s;
else
return "";
} catch(Exception e3) {}
}
}// end of eventNotifier class
code for multithreading handling client requests
public class multiServer
{
static protected List<PrintWriter> writers = new ArrayList<PrintWriter>();
static String client_id = "";
public static void main(String[] args)
{
try
{
ServerSocket servsock = new ServerSocket(8858);
Socket incoming;
while(true)
{
incoming = servsock.accept();
multiServerThread connection = new multiServerThread(incoming);
Thread t1 = new Thread(connection);
t1.start();
}
}
catch(IOException e)
{
System.out.println("couldnt make socket");
}
}
}
class multiServerThread extends Thread implements InterestingEvent
{
Socket incoming;
PrintWriter out=null;
PrintWriter broad=null;
BufferedReader in = null;
String cliString=null;
private EventNotifier en;
int id;
public static String udp_data;
public void interestingEvent(String str1)
{
this.udp_data = str1;
}
public String getUdpData()
{
String _udp_data = this.udp_data;
return _udp_data;
}
multiServerThread(Socket incoming)
{
this.incoming=incoming;
en = new EventNotifier(this);
}
public void run()
{
try
{
out = new PrintWriter(incoming.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
cliString = in.readLine();
multiServer.writers.add(out);
while(true)
{
try
{
udp_data = en.getDataFeed(cliString);
if(udp_data!=null && udp_data.length()>0)
{
//workaround for serving the data to all cleints who are connected
for (int i=0; i<multiServer.writers.size();i++)
{
broad=multiServer.writers.get(i);
broad.println(udp_data.trim());
}
//else will directly write to the outputstream object for every thread which is connected
// out.println(udp_data.trim());
}
}
catch (Exception e)
{
System.out.println("exception "+e);
}
Thread.sleep(1);
}
} catch(IOException e)
{
System.out.print("IO Exception :: "+ e);
}
catch(InterruptedException e)
{
System.out.print("exception "+ e);
}
}
}
You need mutual exclusion (or a different design).
For example, what will happen if two threads call multiServer.writers.add(out); concurrently?
From the ArrayList Javadocs
Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or [...])
Another problem is two calling udp_data = en.getDataFeed(cliString); concurrently. The second thread might overwrite the result of the first. You'll loose data!
What happens if one thread calls for (int i=0; i<multiServer.writers.size();i++) while another thread is busy doing multiServer.writers.add(out);? The size may have increased, before out has actually been added to the list!
public class multiServer
{
private List<PrintWriter> writers = new ArrayList<PrintWriter>();
public synchronized void addWriter(PrintWrite out) {
writers.add(out);
}
public synchronized void serveAllWriters(String data) {
for (int i=0; i<multiServer.writers.size();i++)
{
broad=multiServer.writers.get(i);
broad.println(data);
}
}
}
Now when a thread tries to add a writer, the synchronizeds will make sure no other thread is adding or printing. So multiServerThread should be fixed to use the new methods:
class multiServerThread extends Thread implements InterestingEvent
{
//...
private String udp_data;
//...
myMultiServer.addWriter(out);
//...
udp_data = en.getDataFeed(cliString);
if(udp_data!=null && udp_data.length()>0)
myMultiServer.serveAllWriters(udp_data.trim());
//...
}
There might be more problems, not sure I don't fully understand your code. The question you must ask yourself is, can another thread read and/or write the same data or object? Yes? Then you'll need proper synchronization.

Java concurrent networking issues

I am a Java newbie trying to learn network programming and concurrency, and I thought I'd try out writing a simple chat server where input from a client is echoed to all the clients. That's not happening. I added a couple print statements so that the program will announce that it is waiting for connections and each time it receives a connection. I am using Telnet locally to connect to the port on my machine.
The program announces success for the first and second concurrent connections but then does not announce success for subsequent connections until I close all connections. So, for example, I'll connect from five separate terminals, and the program will announce "Connection 1" and "Connection 2" but will not announce "Connection 3", 4, and 5 until I close all the terminals.
I'm looking for help figuring out where my errors lie as well as general advice for how to approach debugging a situation like this.
In a nutshell, my program has
A Main class, which starts the other three threads
A ClientListener class, which uses a SocketReader to listen for connections and stores the Sockets inputstreams and outputstreams in two Sets.
A MessageReader, which iterates over the inputstreams. If it finds a message, it puts it in a SynchronousQueue and waits for the
MessageWriter to remove it. The MessageWriter sends the message to all the outputstreams.
The code is below. Thanks for any help!
public class Main {
public static void main(String[] args) {
ClientListener clientListener = new ClientListener();
Thread clientListenerThread = new Thread(clientListener);
clientListenerThread.setPriority(Thread.MAX_PRIORITY);
clientListenerThread.start();
MessageReader messageReader = new MessageReader(clientListener);
Thread messageReaderThread = new Thread(messageReader);
messageReaderThread.setPriority(Thread.MIN_PRIORITY);
messageReaderThread.start();
MessageWriter messageWriter = new MessageWriter(messageReader, clientListener);
Thread messageWriterThread = new Thread(messageWriter);
messageWriterThread.setPriority(Thread.NORM_PRIORITY);
messageWriterThread.start();
}
}
public class ClientListener implements Runnable {
private static final int DEFAULT_PORT = 5000;
private Set<Scanner> clientIn = Collections.synchronizedSet(
new LinkedHashSet<Scanner>());
private Set<PrintWriter> clientOut = Collections.synchronizedSet(
new LinkedHashSet<PrintWriter>());
public Set<Scanner> getClientIn() {
return clientIn;
}
public Set<PrintWriter> getClientOut() {
return clientOut;
}
#Override
public void run() {
try {
ServerSocket server = new ServerSocket(DEFAULT_PORT);
System.out.println("Listening for connections...");
int connectionNum = 0;
while(true) {
Socket socket = server.accept();
connectionNum++;
System.out.format("Connection %s%n", connectionNum);
Scanner in = new Scanner(socket.getInputStream());
PrintWriter out = new PrintWriter(socket.getOutputStream());
clientIn.add(in);
clientOut.add(out);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class MessageReader implements Runnable {
private ClientListener clientListener;
private BlockingQueue<String> messages = new SynchronousQueue<String>();
public MessageReader(ClientListener clientListener) {
this.clientListener = clientListener;
}
#Override
public void run() {
while(true) {
Set<Scanner> clients = clientListener.getClientIn();
synchronized (clients) {
for(Scanner client: clients) {
if(client.hasNext()) {
try {
messages.put(client.next());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
public String getMessage() throws InterruptedException {
return messages.take();
}
}
public class MessageWriter implements Runnable {
private ClientListener clientListener;
private MessageReader messageReader;
public MessageWriter(
MessageReader messageReader,
ClientListener clientListener) {
this.messageReader = messageReader;
this.clientListener = clientListener;
}
#Override
public void run() {
try {
while(true) {
String message = messageReader.getMessage();
Set<PrintWriter> clients = clientListener.getClientOut();
synchronized (clients) {
for(PrintWriter client: clients) {
client.println(message);
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I'm not a threading expert, but in class MessageReader there is this line
if(client.hasNext())
Javadoc for Scanner.hasNext() say's "This method may block while waiting for input to scan. The scanner does not advance past any input."
If the scanner is still in wait the synchronized method never proceeds and block all other inputs. And as said in my earlier comment the line which says clientIn.add(in); in class ClientListener probably gets blocked given that its a synchronized Set, but since the print statment is written before it, it might give the impression that Connection 2 was succesfully established.

Categories