Static ArrayList does not modify in another class - java

I am working on a client - server application and I have the following problem.
In one class (Server), I have a static reference to an ArrayList called clients and a static getter getClientsArray(). In another class (ServerThread), I use the same ArrayList and I successfully modify it (add / delete clients).
For every client, I call the method getClientsArray() and get that ArrayList. The problem is that the ArrayList is empty here, in Client class. I check it every time I update it in ServerThread (after a client connects) and it should have something in it.
public class Server {
private static ArrayList<User> clients = new ArrayList<User>();
public static ArrayList<User> getClientsArray() {
return clients;
}
and somewhere I call: new ServerThread(sock, users).start();
}
public class ServerThread extends Thread {
private ArrayList<User> users;
public ServerThread(Socket client, ArrayList<User> users) {
this.client = client;
this.users = users;
}
if I modify users in this class, the changes will occur
}
public class Client extends JFrame {
private ArrayList<User> users;
public Client() {
initGraphics();
users = Server.getClientsArray();
System.out.println(users.size()); <- This line always writes 0!!
}
}

There is a simple rule defined by Brian Goetz in JCIP:
If multiple threads access the same mutable state variable without appropriate synchronization, your program is broken.
You have clients mutable state and you don't use any mean of synchronizing access to it.

Static variables are only global to one program instance. Here, you have at least two programs running; You have one server program, and at least one other client program. The clients and server do not share any common heap, or program variables, so the static list will only be seen by that program.
If you want to share the list, you will need to pass it through sockets or some other data transfer. This question, How to transfer objects over network using java, has a code example of how to pass objects through sockets.

Related

Private variable shares between objects

I have class that looks like
public class Sender {
private LoggingAdapter log = Logging.getLogger(this.toString());
private final ArrayList<CSAMessage> sentHistory = new ArrayList<>();
public void send(final CSAMessage message) {
doSend(message);
sentHistory.add(message);
}
private void doSend(CSAMessage message) {
//do send stuff
}
}
The problem is - when two instances of Sender class are called in same time, they share private sentHistory field. In logs it looks like
Sender1 send(...) was called, message was added to own sendHistory list
Sender2 send(...) was called, message was added to Sender1 sendHistory list
How is that posiible? I'm shure that Sender1 and Sender2 are different instances, they called from different threads, but call was made in same time.
I already tried to make variable 'volatile' - no result
This block gives no result too
private final ArrayList<CSAMessage> sentHistory;
{
sentHistory = new ArrayList<>();
}
Only synchronizing via class helps
public void send(final CSAMessage message) {
synchronized (Sender.class) {
doSend(message);
sentHistory.add(message);
}
}
But this will be performance bottleneck - many Senders must be able to work in same time. And why should i do so? Different instances must use it's own variables!
There are also log variable that has been declared same way, but logging variable not shared between objects, every Sender write logs from it's own name.
Marking the variable final and initializing it the way you did
private final ArrayList<CSAMessage> sentHistory = new ArrayList<>();
// ^^^^^ ^^^^^^^^^^^^^^^^^^^
makes it absolutely impossible for multiple instances to share the same ArrayList.
What remains possible, however, is for multiple ArrayLists to share the same instances of CSAMessage. In cases when shared CSAMessages are mutable, it is possible to create an illusion of sharing. For example, if CSAMessage has a link back to Sender which is set as part of a send call, making a change concurrently may present the message as if it were sent through a wrong sender.

How to store Clients in a list

I am running a server, and I have an arraylist of type Client
When a client connects through
ServerSocket.accept()
I pass the new Socket to the arraylists constructor. This is everything inside the constructor
this.add(new Client(Socket client));
My problem is when a client disconnects, it closes the Socket, but it doesn't delete its spot in the arraylist, and shift everything down one. So the arraylist is constantly growing bigger.
What can I do/use to fix this problem?
Sometimes I will run commands that will execute on all clients which is why I store the clients in an arraylist.
Is there a better alternative for storing clients in a server?
Update 1
The classes are in the beginning stages. Very little has been implemented. So far the HashMap option suggested in the answer works best for me. Thank you for your replies
Interesting problem.
You should use hash map here .. Add the client with object as value and use some key. Whenever you disconnect it, remove it from the map.
A good question could me what should be the key? may be the object reference (depends on your choice) or anything that is unique with respect to client object (there must be something, if not, you can generate it easily).
Map<Integer,Client> clientMap = new HashMap<Integer,Client>();
You should remove the Client from the ArrayList, the rest elements in the list will automatically shuffle upwards along the list.
//java.util.ArrayList.remove(Object) shifts any subsequent elements
// to the left (subtracts one from their indices).
Say,if the Client is Client A and the ArrayList is ArrayListA, then you should apply
ArrayListA.remove(ClientA);
But, the better approach would be to use HashMap to store client information as mentioned in Danyal Sandeelo's answer.
A lot of assumptions are made, for example I'm assuming you have a disconnect() method in your Client class. Please provide more details if you want a more accurate solution.
One way of doing it could be by passing a callback to your client so it removes itself from the ArrayList when it's done. Very rough implementation:
public class Callback {
private ArrayList<Client> clients;
public Callback(ArrayList<Client> clients) {
this.clients = clients;
}
public void remove(Client client) {
clients.remove(client);
}
}
Then pass the Callback when you instantiate the Client:
Callback callback = new Callback(list);
list.add(new Client(socket, callback));
Then call the remove() method of the callback. If the Client has a disconnect() method, then inside it you can do
public void disconnect() {
// bla bla
callback.remove(this);
}
This way the Client can clean up after itself when it needs to :)
If Client it's your own class, then you can try this one:
public class Client {
public final List<Client> clients;
public Client(List<Client> clients, Socket socketClient) {
this.clients = clients;
clients.add(this);
}
public void disconnect() {
clients.remove(this);
}}
List<Client> clients = new ArrayList<Client>();
new Client(clients, new Socket());
new Client(clients, new Socket());
new Client(clients, new Socket());

How to make thread safe singleton class which can accepts parameter?

I am trying to make a class as ThreadSafe Singleton but somehow I am not able to understand how to make ThreadSafe Singleton class which can accepts parameter.
Below is the class which I am using from this github link which I am using currently to make a connection to Zookeeper -
public class LeaderLatchExample {
private CuratorFramework client;
private String latchPath;
private String id;
private LeaderLatch leaderLatch;
public LeaderLatchExample(String connString, String latchPath, String id) {
client = CuratorFrameworkFactory.newClient(connString, new ExponentialBackoffRetry(1000, Integer.MAX_VALUE));
this.id = id;
this.latchPath = latchPath;
}
public void start() throws Exception {
client.start();
client.getZookeeperClient().blockUntilConnectedOrTimedOut();
leaderLatch = new LeaderLatch(client, latchPath, id);
leaderLatch.start();
}
public boolean isLeader() {
return leaderLatch.hasLeadership();
}
public Participant currentLeader() throws Exception {
return leaderLatch.getLeader();
}
public void close() throws IOException {
leaderLatch.close();
client.close();
}
public CuratorFramework getClient() {
return client;
}
public String getLatchPath() {
return latchPath;
}
public String getId() {
return id;
}
public LeaderLatch getLeaderLatch() {
return leaderLatch;
}
}
And this is the way I am calling the above class -
public static void main(String[] args) throws Exception {
String latchPath = "/latch";
String connStr = "10.12.136.235:2181";
LeaderLatchExample node1 = new LeaderLatchExample(connStr, latchPath, "node-1"); // this I will be doing only one time at just the initialization time
node1.start();
System.out.println("now node-1 think the leader is " + node1.currentLeader());
}
Now what I need is if I am calling these two below methods from any class in my program, I should be able to get an instance of it. So I am thinking to make above class as a Thread Safe Singleton so that I can access these two methods across all my java program.
isLeader()
getClient()
How do I make above class as ThreadSafe singleton and then make use of isLeader() and getClient() across all my classes to see who is the leader and get the client instance..
I need to do this only at the initialization time and once it is done, I should be able to use isLeader() and getClient() across all my classes.. Is this possible to do?
// this line I will be doing only one time at just the initialization time
LeaderLatchExample node1 = new LeaderLatchExample(connStr, latchPath, "node-1");
node1.start();
This is more of Java question not Zookeeper stuff..
A singleton which requires a parameter is a bit of a contradiction in terms. After all, you'd need to supply the parameter value on every call, and then consider what would happen if the value was different to an earlier one.
I would encourage you to avoid using the singleton pattern at all here. Instead, make your class a perfectly normal one - but use dependency injection to provide a reference to a single configured instance to all your classes that need it.
That way:
The singleton nature isn't enforced, it's just a natural part of you only needing one reference. If later on you needed two references (e.g. for different Zookeeper instances for some reason) you can just configure the dependency injection differently
The lack of global state generally makes things much easier to test. One test might use one configuration; another test might use a different one. No singleton, no problem. Just pass the relevant reference into the constructor of the class under test.

Java Static Factory conversion

On my Client/Server Desktop application. I have this problem of how I should properly code my JDBC class with my Models to ensure all persistence request can support concurrency. i.e., multiple models want to request update to its persistence counterpart simultaneously [without atmost delay].
The scenario goes like this. Following the classes located in the server application.
Persitence Package:
abstract class AbstractService {
// other fields
private final String tName, tId;
private final String sqlStatement;
public AbstractService(final String tName, final String tId) {
this.tName = tName;
this.tId = tId;
this.sqlStatement = ""; // SELECT statement
}
// java.sql.Connection() createConnection()
// methods
}
public class T1Service extends AbstractService {
private final String sqlDMLStatements;
public T1Service() {
super("t1", "t1Id");
this.sqlDMLStatements = ""; // other DML statements
}
// methods having return types of List<E>, Object, Boolean, etc.
// i.e., public List<E> listAll()
}
Communication class [Client class]
import java.net.*;
import java.io.*;
public class Client extends Observable{
private Socket socket;
private ObjectInputStream input;
private ObjectOutputStream output;
private Object message;
// Constructor
// Getters/Setters
// Other methods like open or close input/output
private class ReceiverRunnable implements Runnable
#Override
public void run() {
while(running) { // if socket is still open and I/O stream are open/initialized
try { message = input.readObject(); }
catch(Exception e) {}
finally { setChanged(); notifyObservers(); }
}
}
}
}
The Main Class [Server class]
import java.net.*;
public class Server {
private List<Client> clientList; // holds all active connections with the server
private T1Service t1Service
private class ConnectionRunnable implements Runnable {
#Override public void run() {
while(running) { // serverSocket is open
Client client = new Client(ServerSocket.accept(), /* other parameters */);
client.addObserver(new ClientObserver(client));
clientList.add(client);
}
}
}
private class ClientObserver implements Observer {
private Client client;
// Constructor
public void update(Observable o, Object arg) {
// Check the contents of 'message' to determine what to reply
// i.e., message.equals("Broadcast") {
// synchronized(clientList) {
// for(Client element : clientList) {
// element.getOutput().writeObject(replyObject);
// element.getOutput()..flush();
// }
// }
// i.e., message.equals("T1") {
// synchronized(t1Service) {
// client.getOutput().writeObject(t1.findAll());
// client.getOutput().flush();
// }
}
}
}
Since this is a Client/Server applcation, multiple request from the client are simultaneously feed to the server. The server process the request sending the appropriate reply to the approriate client. Note: All of the objects sent between Client & Server an instance of java.io.Serializable.
Having this kind of scenario and looking into the block of Server.ClientServer.update() we may have a performance issue or I should say a delay in processing the N client(s) request due to Intrinsic Locks. But since I have to the rules concurrency and synchronization to ensure that Server.T1Service won't get confused to the queue of N clients request to it. Here's are the questions:
According to the Item 1 of Effective Java - Second Edition regarding Static Factory, would this let me create a new class reference to the methods inside the classes of Persistence package?
Would each Client element inside List<Client> would form a concurrency issue having N client update their message field simultaneously triggering the ClientObsver.update() wherein the reference object(s) of this Observer is only a single instance in the parent class. I was avoiding creating multiple instance of T1Service due to memory concerns.
If we are going to go by the contents of Effective Java - Second Edition, how can I convert my persitence class in a way they can be read easily, easily instantiated, and support concurreny?
you may also want to review Actors, for example ones in Akka
basic idea of actors is avoiding of synchronization at all, using sending events. Akka will guarantee that one actor will never be invoked by two threads in parallel. So you may define actor, which does something with the global variables, and then simply send a message to it.
works like a charm usually :)
Is my theory of [Item 1] Static Factory correct?
Yes, you can use a static factory instead of constructors. Typically this is when you the construction logic is complex and shared between various subtypes to warrant a factory pattern. Additionally the factory may provide means for dependency injection outside of a DI framework.
Would it then solve the concurrency issue of the converted static factory global objects?
If you need to synchronize construction, then a static factory works well, just add synchronized to the method declaration on your factory methods. If you need to synchronize methods on the objects themselves then this will not help.
Is it advisable for me to convert to static factory if where dealing with concurrent access to a global object and where wanted real-time access to the methods of each global object?
As I answered above, it depends on what you are trying to achieve. For constructor synchronization use a factory.

Java Serialization of referenced objects is "losing values"?

Good day,
I am having an interesting problem that I cannot understand. I have a class called "HomeScreenManager" which maintains a LinkedList<String> called chat. The HomeScreenManager instance lives on the server and is in charge of keeping track of the connections and the chat log. I then created a class called "ProtocolHomeScreen" which is a class with a LinkedList<String> called chat and implements Serializable. When it comes time to update all the clients with the chat, I want to send out a ProtocolHomeScreen. So I create a brand new instance of the ProtocolHomeScreen and I say that it's linked list of strings "gets" the HomeScreen's linked list. So in other words, the linked list that I want to serialize was created in a different class, but I am pointing to it with another instance. The problem is that the data does not get sent, only an empty LinkedList appears on the other side. I've done the debugger line by line and inspected all the variables and right before I call writeObject everything appears to be fine, but then on the client side, when I receive the ProtocolHomeScreen instance, the linked list is empty! (its not null though) Any ideas? Thank you!
public class HomeScreenManager implements ObjectMessageHandler, Serializable
{
protected LinkedList<User> users;
protected LinkedList<String> chat;
protected LinkedList<String> sessions;
public HomeScreenManager()
{
chat = new LinkedList<String>();
users = new LinkedList<User>();
sessions = new LinkedList<String>();
}
protected void handleChat(String message)
{
chat.add(message);
ProtocolHomeScreen p = new ProtocolHomeScreen(this);
for(User u:users)
{
u.connection.WriteObject(p); //At this point in time, p has the correct data, but when I deserialize p, the chat list is empty...
}
}
Then here is the protocol class...
public class ProtocolHomeScreen implements Serializable
{
public LinkedList<String> chat;
public LinkedList<String> players;
public LinkedList<String> sessions;
public ProtocolHomeScreen(HomeScreenManager hms)
{
players = new LinkedList<String>();
for(User u:hms.getUsers())
{
players.add(u.getUsername());
}
sessions = hms.getSessions();
chat = hms.getChat();
chat = new LinkedList<String>();
for(String s: hms.getChat())
{
chat.add(s);
}
}
}
Edit
This is the code on the client side... note that the player's LinkedList comes across just fine, but I think that has something to do with the fact that I created a new instance in the constructor of the ProtocolHomeScreen (on the server side)
else if(obj instanceof ProtocolHomeScreen)
{
ProtocolHomeScreen phs = (ProtocolHomeScreen) obj;
sessionModel.removeAllElements();
playersModel.removeAllElements();
chatOutput.setText("");
for(String s:phs.players)
playersModel.addElement(s);
for(String s:phs.sessions)
sessionModel.addElement(s);
for(String s:phs.chat)
{
chatOutput.setText(chatOutput.getText()+s);
}
}
You need to look at ObjectOutputStream.reset() and why it exists. Any given object is only sent once over an ObjectOutputStream unless you reset() the stream or use writeUnshared().

Categories