Confusion with Synchronization and inter thread communication - java

I've been given this question and I've been trying since days but I'm not able to get the correct output. Any help would be appreciated.
Develop a simple chat application between two users using Send-Wait-Receive Protocol:
Once a user sends a message, he waits until a message is received from the other user. The users are "User1" and "User2".
At initial stage of application, User1 is in sending mode and User2 is in receiving mode. These two users are sending and receiving the messages alternatively.
-Create a Chat class with two methods: sendMessage and recvMessage
-Create two threads to represent two users,User1 and User2.
-Use Interthread communication to exchange messages.
-No need to maintain any chat history.
OUTPUT:
User1(User2):HI
User2(User1):HI
User2(User1):Hello
User1(User2):Hello
class Chat{
Scanner sc=new Scanner(System.in);
String message;
ArrayList<String> user1 = new ArrayList<String>();
ArrayList<String> user2 = new ArrayList<String>();
boolean sendMode = true;
String name = "";
String otherName = "";
synchronized void recvMessage(){
name = Thread.currentThread().getName();
while(sendMode) {
try{
wait();
}catch(InterruptedException e){
System.out.println("InterruptedException caught");
}
}
System.out.println(name);
if (name.contentEquals("User1")) {
otherName="User2";
}
else {
otherName="User1";
}
System.out.println(name+"("+otherName+"):" + message);
sendMode=true;
System.out.println("rcv");
notify();
}
synchronized void sendMessage(){
name = Thread.currentThread().getName();
while(!sendMode) {
try{
wait();
}catch(InterruptedException e){
System.out.println("InterruptedException caught");
}
}
System.out.println(name);
if (name.contentEquals("User1")) {
otherName="User2";
}
else {
otherName="User1";
}
System.out.print(name+"("+otherName+"):");
message=sc.next();
if(name.contains("User1")) {
user1.add(message);
}
else {
user2.add(message);
}
System.out.println("send");
sendMode=false;
notify();
}
}
class Person1 implements Runnable{
Chat ex;
public Person1(Chat ex) {
this.ex = ex;
Thread u2=new Thread(this, "User1");
u2.start();
}
public void run() {
while(true) {
ex.sendMessage();
}
}
}
class Person2 implements Runnable{
Chat ex;
public Person2(Chat ex) {
this.ex=ex;
Thread u1=new Thread(this, "User2");
u1.start();
}
public void run() {
while(true) {
ex.recvMessage();
}
}
}
class Main{
public static void main(String args[])
{
Chat ex =new Chat();
new Person1(ex);
new Person2(ex);
}
}
the output I'm getting is:
User1(User2):hi
User2(User1):hi
User2(User1):hello
User1(User2):hello
User2(User1):what's up
User1(User2):what's
User2(User1):User1(User2):up
User2(User1):
Basically the threads are not in doing their job in order. The first 4 lines of output are right. But after that, it's always user2 sending the message and user1 receiving it.
Please help me out.

There is two issues with your code first is that you are using:
message=sc.next();
and instead you should be using:
message=sc.nextLine();
Using next() will only return what comes before the delimiter
(defaults to whitespace). nextLine() automatically moves the scanner
down after returning the current line.
From this SO thread.
That is why for the first inputs without spaces it works fine, but as soon as you send a string with spaces:
what's up
you ran into problems.
The second part is that with your current design only one of the threads send and another receives. For having both communication with each other instead of a monologue, I would suggest to do something like:
class Chat{
Scanner sc=new Scanner(System.in);
String message;
final Object rec = new Object();
final Object send = new Object();
boolean msg_send = false;
boolean msg_recv = false;
void recvMessage(){
synchronized (send){
while(!msg_send) {
try{
send.wait();
}catch(InterruptedException e){
System.out.println("InterruptedException caught");
}
}
msg_send = false;
}
synchronized (rec) {
String name = Thread.currentThread().getName();
System.out.println(name);
String otherName = name.contentEquals("User1") ? "User2" : "User1";
System.out.println(name + "(" + otherName + "):" + message);
System.out.println("rcv");
msg_recv = true;
rec.notify();
}
}
void sendMessage(){
synchronized (send) {
String name = Thread.currentThread().getName();
System.out.println(name);
String otherName = name.contentEquals("User1") ? "User2" : "User1";
System.out.print(name + "(" + otherName + "):");
message = sc.nextLine();
System.out.println("send");
msg_send = true;
send.notify();
}
synchronized (rec) {
while (!msg_recv) {
try {
rec.wait();
} catch (InterruptedException e) {
System.out.println("InterruptedException caught");
}
}
msg_recv = false;
}
}
}
class Person1 implements Runnable{
Chat ex;
public Person1(Chat ex) {
this.ex = ex;
Thread u2=new Thread(this, "User1");
u2.start();
}
public void run() {
while(true) {
ex.sendMessage();
ex.recvMessage();
}
}
}
class Person2 implements Runnable{
Chat ex;
public Person2(Chat ex) {
this.ex=ex;
Thread u1=new Thread(this, "User2");
u1.start();
}
public void run() {
while(true) {
ex.recvMessage();
ex.sendMessage();
}
}
}
class Main{
public static void main(String args[])
{
Chat ex =new Chat();
new Person1(ex);
new Person2(ex);
}
}
Waiting and notifying using two objects representing when the message was received and send:
final Object rec = new Object();
final Object send = new Object();
Then you need the reason about when should you synchronize on one or the other object.

Related

Concurrency issue with threads

I have a simple code, consisting of 4 threads (2 modify the data and 2 read the data). I just wrote this sample code to play around with Semaphor and I am not sure why I get ava.base/java.util.ArrayList$Itr.checkForComodification exception? Here are the source code and thanks for any insights.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
public static class InnerWriterSemaphoreThread implements Runnable {
private final List<String> fList;
private final Semaphore fWriteSem;
InnerWriterSemaphoreThread(List<String> list, Semaphore w) {
fList = list;
fWriteSem = w;
}
private void prune() {
System.out.println(Thread.currentThread().getName()+" in prune()..");
for (String s : fList) {
fList.remove(s);
}
}
#Override
public void run() {
String name = Thread.currentThread().getName();
String text;
while (true) {
text = RandomTextGenerator.getRandomSNumbertring();
try {
while(!fWriteSem.tryAcquire()){
System.out.println(name+" waiting to accquire semaphore to write..");
Thread.sleep(0L,4);
}
if (fList.size() > 10) {
prune();
}
fList.add(text);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
fWriteSem.release();// notify readers that write has completed
System.out.println(name+" finished writing, releasing semaphore..");
}
}//while()
}//run()
}//WriterSemaphoreThread
public static class InnerReaderSemaphoreThread implements Runnable {
private final List<String> fList;
private final Semaphore fWriteSem;
InnerReaderSemaphoreThread(List<String> list,Semaphore w) {
fList = list;
fWriteSem = w;
}
private void sleep(){
try{
Thread.sleep(0L, 4);
}catch(InterruptedException e){
e.printStackTrace();
}
}
#Override
public void run() {
String name = Thread.currentThread().getName();
while (true) {
System.out.println(name + " in run()..");
try {
while(fList.isEmpty()){
System.out.println(name+" list is empty, going to sleep..");
sleep();
}
while(!fWriteSem.tryAcquire()){
System.out.println(name+" waiting to accquire semaphor to read..");
Thread.sleep(0l,4);
}
for (String text : fList) {
System.out.println(name + " reading from list " + text);
}
}catch (InterruptedException e) {
e.printStackTrace();
}
finally{
fWriteSem.release(); //Notify threads who want to write to the list
System.out.println(name+" finished reading, releasing semaphore and going to sleep..");
sleep();
}
}
}
}//ReaderSemaphoreThread
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Semaphore r = new Semaphore(1);
Thread th1 = new Thread(new InnerWriterSemaphoreThread(list, r), "Thread 1");
Thread th2 = new Thread(new InnerReaderSemaphoreThread(list, r), "Thread 2");
Thread th3 = new Thread(new InnerWriterSemaphoreThread(list, r), "Thread 3");
Thread th4 = new Thread(new InnerReaderSemaphoreThread(list, r), "Thread 4");
th2.start();
th4.start();
th1.start();
th3.start();
}
}
Above is the sample source code
As #assylias mentioned in comment it happens when you remove elements from list in foreach loop. Just replace
for (String s : fList) {
fList.remove(s);
}
with
fList.clear();

Stopping waiting threads on condition

I am learning multithreading. I am implementing producer and consumer problem. I am stuck on scenario where i want that when I press anything apart from integer from keyboard, all my threads should die and there is no memory in use by threads. Please have your valuable inputs to help me achieve it. Below is all the code I am using.
package com.java.concurrency;
public class ThreadSignaling {
private int i = -1;
private boolean valueSet = false;
private boolean stopFlag = false;
public void put(int value) {
synchronized (this) {
while (valueSet) {
if (stopFlag) {
System.out.println("Byeeeeeeeeeeeee");
break;
}
try {
this.wait();
} catch (InterruptedException e) {
System.out.println("InterruptedException while waiting in put() : " + e);
}
}
this.i = value;
this.valueSet = true;
System.out.println("Value put : " + this.i);
this.notify();
}
}
public void get() {
synchronized (this) {
while (!valueSet) {
if (stopFlag) {
System.out.println("Byeeeeeeeeeeeee");
break;
}
try {
this.wait();
} catch (InterruptedException e) {
System.out.println("InterruptedException while waiting in get() : " + e);
}
}
System.out.println("Value get : " + this.i);
valueSet = false;
this.notify();
}
}
public void finish() {
synchronized (this) {
stopFlag = true;
this.notifyAll();
}
}
}
public class Producer implements Runnable {
private ThreadSignaling sharedObj = null;
private final Scanner input = new Scanner(System.in);
public Producer(ThreadSignaling obj) {
this.sharedObj = obj;
}
#Override
public void run() {
int value = -1;
System.out.println("Press Ctrl-c to stop... ");
while (true) {
System.out.println("Enter any integer value : ");
if (input.hasNextInt()) {
value = input.nextInt();
} else {
this.sharedObj.finish();
return;
}
this.sharedObj.put(value);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println("InterruptedException while sleeping" + e);
}
}
}
}
public class Consumer implements Runnable {
private ThreadSignaling sharedObj = null;
public Consumer(ThreadSignaling obj) {
this.sharedObj = obj;
}
#Override
public void run() {
while (true) {
this.sharedObj.get();
}
}
}
public class MainThread {
public static void main(String[] args) {
ThreadSignaling sharedObj = new ThreadSignaling();
Producer in = new Producer(sharedObj);
Consumer out = new Consumer(sharedObj);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
} enter code here
The problem with your code is that you do not have an exit condition for the Consumer. The run() method of the Consumer will run forever, and while doing repeated get calls on the shared object.
What you need to do is to make aware the Consumer that the Producer has set the stopFlag in the shared object. And if that stopFlag is true then the loop in the Consumer should also finish. There are several ways you can do that:
redefine get method to return the value of stopFlag;
define a new method to return just the value of stopFlag;
In either cases, make a test in the Consumer.run() and if the value is true, just do a return so the infinite loop ends.

Removing users from chat (Java)

I have developed a client/server chat application using Java and I wish to know how can I remove a user from an array. When a specific client log-in the username is saved in username array and client ID in client array. To allow the server to accept multiple clients, I am using threads. Now can anyone guide me on how to remove a user from the array and also close the connection for that user.
Adding a new client and saving the ID in client array
public class AddClient implements Runnable {
Thread t;
AddClient(String tot) {
t = new Thread(this, tot);
t.start();
}
public void run() {
while (true) {
try {
try {
waitClient();
} catch (Exception ex) {
ex.printStackTrace();
}
for (int i = 0; i < client.length; i++) {
if (client[i] == 0) {
client[i] = i + 1;
id = i;
break;
}
}
//set stream to send and receive data
out[client[id]] = new ObjectOutputStream(connect.getOutputStream());
out[client[id]].flush();
in[client[id]] = new ObjectInputStream(connect.getInputStream());
The username is saved in the username array
username[client[id]] = cm.sender; //Add user in username[] array
Removing user
public synchronized void removeUser(int number) {
int position = number;
System.out.println("Server removing user " + username[number] + "which is client " + number);
for (int i = 0; i <= client.length; i++) {
if (position == client[i]) {
System.out.println("User to be remove found");
try {
client[i + 1] = client[i];
in[position].close();
out[position].close();
username[position] = null;
position = position - 1;
} catch (Exception e) {
e.printStackTrace();
}
}
}
I am trying to use HashTable to add and remove the client
public class ChatServerProtocol {
private String nick;
private AddClient a;
private Hashtable<String, AddClient> nicks = new Hashtable<String, AddClient>();
private boolean add_nick(String nick, AddClient a) {
if (nicks.containsKey(nick)) {
return false;
} else {
nicks.put(nick, a);
return true;
}
}
private boolean remove_nick(String nick, AddClient a) {
if (!(nicks.containsKey(nick))) {
return false;
} else {
nicks.remove(nick);
return true;
}
}
public ChatServerProtocol(AddClient a) throws IOException {
nick = null;
a = a;
}
But now how do I call the method add_nick. Whenever a client log-in the username is sent to the server and the server reads it as cm.sender. I also need to include the thread variable. So how to add the username so that later i can remove it.
ChatServerProtocol.add_nick(cm.sender);
No, saving in database won't be a good idea.. Remember you are saving details only for the length of the session and basic concept of database is to use it after the session. What happens if your session gets interruped because of network issues etc?
Just use Map instead of plain arrays, using key as client ID and value as username.. removing username will be a plain call such as map.remove(clientID);
EDIT AS YOU ASKED: Note that this code is not complete and only as much as you gave..
public class AddClient implements Runnable {
Thread t;
private Map<int, String> users = new HashMap <int, String>();
AddClient(String tot) {
t = new Thread(this, tot);
t.start();
}
public void run() {
while (true) {
try {
try {
waitClient();
} catch (Exception ex) {
ex.printStackTrace();
}
int clientId = users.size() + 1;
users.put(clientId, cm.sender);
//set stream to send and receive data
out[clientId] = new ObjectOutputStream(connect.getOutputStream());
out[clientId].flush();
in[clientId] = new ObjectInputStream(connect.getInputStream());
REMOVE USER METHOD
public synchronized void removeUser(int number) {
if(users.containsKey(number)) {
System.out.println("Server removing user " + users.get(number) + "which is client " + number);
users.remove(number);
} else {
System.out.println("User not in session");
}
}

Syncronizing a multithreaded server

Hello everyone i have created a multi threaded chat server that looks like this:
public class Main {
public static ServerSocket server;
public static Socket connection;
public static int backLog = 100;
public static int numberOfConnected;
public static boolean connected = false;
public final static int potNumber = 6080;
public static PrintWriter pw;
public static Scanner input;
public static int i = 0;
public static void main(String[] args) {
startServer();
}
public static void startServer(){
try {
server = new ServerSocket(potNumber, backLog);
waitingForConnection();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void waitingForConnection() {
connected = false;
i++;
while (!connected) {
try {
if (connected) {
}
connection = server.accept();
Server s = new Server(connection, pw = new PrintWriter(connection.getOutputStream()), input = new Scanner(connection.getInputStream()));
s.start();
numberOfConnected++;
waitingForConnection();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
The idea is that this is suppose to be a chat server so when one connects to the server it starts the following thread:
threads
public void run(){
while (connection.isConnected()) {
if (input.hasNext()) {
String fullMessage = input.nextLine();
if (fullMessage.equalsIgnoreCase("Connect")) {
connectHim();
}else {
chatMessage(fullMessage);
}
}
}
}
private void chatMessage(String fullMessage) {
String name = fullMessage.substring(0, fullMessage.indexOf(" "));
String message = fullMessage.substring(fullMessage.indexOf(" "), fullMessage.length());
pw.println(name+": "+message);
pw.flush();
}
private void connectHim() {
String name = input.nextLine();
pw.println(0);
pw.flush();
pw.println(1);
pw.flush();
pw.println();
pw.flush();
pw.println(name);
pw.flush();
}
So my problem is the following:
if the user that is bound to thread 1 (this is an example) and the user bound to thread 2 sends a message to the server how will i send that message to the user bound on thread 1?
One of options is to use Hashtable or HashMap (just call Collections.synchronizedMap(myMap) in case of Map usage). When you start new Thread, give him unique name (for example user nick name ) and put it to your collection where key - Thread name, and value - Thread as Object.
if the user that is bound to thread 1 (this is an example) and the user bound to thread 2 sends a message to the server how will i send that message to the user bound on thread 1?
For example you have user1, user2, user3. Now you build 3 Threads and put them to HashMap, like:
Map<String, Thread> threadMap = new HashMap<String,Thread>();
threadMap = Collections.synchronizedMap(threadMap);
YourThread th1 = new YourThread();
threadMap.put("user1", th);
YourThread th2 = new YourThread();
threadMap.put("user2", th);
YourThread th3 = new YourThread();
threadMap.put("user3", th);
....
Set<String> userSet = threadMap.keySet();
Iterator<String> it = userSet.iterator();
Thread currThread = null;
while(it.hasNext()){
String key = it.next();
currThread = threadMap.get(key);
// do something with currThread
}

How to make the same program act like a server and client (using sockets in java)

How can I send and receive from the same program in java ? To make matters worse, I need to do both in the same time in parallel.
You need a well behaved queue such as a BlockingQueue between two Threads.
public class TwoThreads {
static final String FINISHED = "Finished";
public static void main(String[] args) throws InterruptedException {
// The queue
final BlockingQueue<String> q = new ArrayBlockingQueue<String>(10);
// The sending thread.
new Thread() {
#Override
public void run() {
String message = "Now is the time for all good men to come to he aid of the party.";
try {
// Send each word.
for (String word : message.split(" ")) {
q.put(word);
}
// Then the terminator.
q.put(FINISHED);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
{ start();}
};
// The receiving thread.
new Thread() {
#Override
public void run() {
try {
String word;
// Read each word until finished is detected.
while ((word = q.take()) != FINISHED) {
System.out.println(word);
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
{ start();}
};
}
}

Categories