I have a class that creates multiple threads, each thread gets an socket as parameter in constructor.
I need to synchronize the threads, so that only one thread accesses the sockets streams at given time.
Here is quick draft of what I need:
class MyClass{
Socket socket;
public MyClass() {
socket = new Socket(address, port);
}
void createThread(){
Worker worker = new Worker(socket);
Thread t = new Thread(worker);
t.start();
}
void doStuff(){
InputStream is = socket.getInputStream();
/* ... */
}
}
class Worker implements Runnable{
Socket socket;
public Worker(Socket socket){
this.socket = socket;
}
#Override
public void run() {
InputStream is = socket.getInputStream();
/* ... */
}
}
Now here, potentially multiple threads can access sockets input stream at the same time, which would be very bad.
Now my question is: will synchronized keyword work for this case?
To use basic synchronization you could use the socket as the lock since it's shared by each worker.
public void run() {
synchronized (socket) {
InputStream is = socket.getInputStream();
/* ... */
}
}
If MyClass really needs to access the socket as well, perform the same synchronization in doStuff.
However, you're effectively serializing access to the socket and bypassing the multi-threaded aspect of your application since the lock is held during the entire duration of the run method.
Related
I have a list of the socket in the main function, add a new socket when a new client connects to the server.
public static void main(String[] args) throws Exception {
// TODO code application logic here
server = new ServerSocket(port);
List<MySocket> sockets = new ArrayList<>();
//this is thread responsible to synchronizing
new SyncThread().start();
while(true){
Socket socket = server.accept();
MySocket mySocket = new MySocket(socket);
sockets.add(mySocket);
SocketThread.setSockets(sockets);
new SocketThread(mySocket).start();
}
}
Besides that, I also want to create a new thread that will synchronize the list of this socket to the client (by sending the list to clients periodically).
public class SyncThread extends Thread{
private static List<MySocket> sockets;
#Override
public void run(){
//send list sockets to client
}
}
How to I synchronize the list of the socket between the main function and SyncThread?
Make your list a synchronized list:
List<MySocket> sockets = Collections.synchronizedList(new ArrayList<>());
And then pass this as a constructor parameter to SyncThread:
new SyncThread(sockets).start(); // Need to add constructor parameter to class.
public class SyncThread extends Thread{
private final List<MySocket> sockets; // NOT static.
public SyncThread(List<MySocket> sockets) {
this.sockets = sockets;
}
...
}
Bear in mind that this doesn't make sockets synchronized for compound operations, e.g. iteration. For that, you'd need to explicitly synchronize on sockets; or choose a different type of list such as CopyOnWriteArrayList, which is inherently thread-safe (the choice depends on the read/write characteristics of how you use the list).
Additionally, it's rarely appropriate to extend Thread directly. Instead, pass it a Runnable:
new Thread(() -> { /* send list sockets to client */ }).start();
I have created and connected socket in one thread. Can I use the same Socket object in another thread?
Them same question is about OutputStream. Can I use it differn threads.
Socket s = null;
//create and connect cocket
//...
OutputStream out = s.getOutputStream();
For example, can I write data from different threads?
out.write(byteArr);
Of course, you can use a variable in class whitch extends Thread. For Example:
public class MyClass extends Thread {
Socket s;
public MyClass(Socket s){
...
this.s = s;
}
#Override
public void run(){
... your code and usage of socket
OutputStream out = s.getOutputStream();
out.write(byteArr);
}
}
In a main class or where you want
Myclass m = New MyClass(mySocket);
m.start();
I have to do a cluedo game for Uni, so we have a Server class and Clients that are connecting. For each Client connecting we want to start a own ServerThread with the socket of the Client that is connecting. This Thread just listens to incoming messages and tells the server class to send them back to the client(s).
PROBLEM: each time a new client connects he is overwriting this ServerThread so there is always just one ServerThread and we would like to have one for each Client. We send JSON messages between the Clients and right now the receive message in the ServerThread reads only from the last connected socket. How can i solve this? i added my accept method in the Server i guess the mistake is there but could be anywhere. Thanks for your help!
Mauritius
Server
public void accept() throws IOException{
while(true){
Socket socket = serverSocket.accept();
Runnable r = new ServerThreadHandler(socket);
Thread t = new Thread(r);
t.start();
}
}
ServerThreadHandler:
public class ServerThreadHandler implements Runnable {
static Socket socket=null;
protected User client;
//private static int i;
private static BufferedReader in;
private static OutputStreamWriter out;
public void createUser(String nick, String group, String[] ext) throws IOException{
client = new User(nick, group, ext, null, false, 0, false, socket, socket.getPort());
}
/**
* constructor-Method
* #param socketS
*/
ServerThreadHandler(Socket socketS){
socket = socketS;
}
public void run(){
Server.setThreadList(socket);
in = createReader();
out = createWriter();
//and so on...
}
}
The logic mentioned in you code snippet will definitely create as many threads as the no. of clients that are connecting.
However, the possible reason might be, since the Socket variable in ServerThreadHandler is Static, all subsequent threads being created overwrite the same socket variable causing issue in the previously created thread which is using the socket variable.
You should consider, using non static variable for the Socket in ServerThreadHandler since any runnable class should hold a state and should not be using a static socket.
From what I understood from your question,
createUser method is an instance method of ServerThreadHandler. Hence you must have created the instance of ServerThreadHandler to invoke createUser from another class. Hence you can access the socket variable even if it is an instance variable.
Unfortunately the code has many design flaws:
The quickest fix I can suggest is to remove User class and move everything in the Handler class (or vice verca ? )
also make all your variable non-static
static Socket socket=null;
protected User client;
//private static int i;
private static BufferedReader in;
private static OutputStreamWriter out;
they should be :
Socket socket=null;
protected User client;
//private int i;
private BufferedReader in;
private OutputStreamWriter out;
The Socket member variable should be non-static. Ditto the reader and writer.
Never make a variable static unless you have a really good reason to do so and understand the consequences.
I am trying to make a chat server (as a smaller part of a game I'm coding) that accepts two clients. The way I have done this so far is by creating two completely different sets of a Socket, ObjectInputStream, and ObjectOutput stream.
private JTextField userText;
private JTextArea chatWindow;
private ObjectOutputStream output;
private ObjectInputStream input;
private ObjectOutputStream output2;
private ObjectInputStream input2;
private ServerSocket server;
private Socket connection;
private Socket connection2;
static final int PORT = 6789;
The outputting is working just fine, but the input method is not working as planned. This is the input method:
//runs while conversation is active
private void whileChatting() throws IOException{
waitForConnection();
setupStreams();
String message = " You are now connected! ";
sendMessage(message);
ableToType(true);
do{
message = input.readUTF();
showMessage("\n" + message);
message = input2.readUTF();
showMessage("\n" + message);
}while(!message.contains("END"));
}
The line message = input.readUTF(); is waiting for there to be something to read. Is there a way to check if there is something to read and only set message equal to it if not null? No, if(input.readUTF() != null) does not work. Alternatively, I think there would be a way to do this with multiple threads, but I do not have a good grasp on how threads work, so if someone could give me an example, that would be very helpful.
Thanks.
readUTF() is considered a blocking call, which means when it is called, it will hold up the thread until it returns a value. Even if you were to nullcheck, it will still block your thread from continuing until something came through the stream (whether it be a string or a null).
To handle something like a multithreaded connection:
Create a class that implements Runnable
class User implements Runnable {
}
In that class, add you in\out stream. Make sure they're aren't static so they're instance variables. You are gonna want a new in/out stream for each connection
class User implements Runnable {
DataOutputStream out;
DataInputStream in;
Socket socket;
public User(Socket s) {
socket = s;
}
public void run() {
try {
out = new DataOutputStream(socket.getOutputStream());
//same with inputstream
String input;
while(!(input = in.readUTF()).equals("END")) {
//do something with input
}
}
}
}
When your server accepts a connection...
public static void main(String[] args) {
ExecutorService executors = Executors.newCachedThreadPool(); //contains your threads
ServerSocket ss;
while(true)
executor.execute(new User(ss.accept()));
}
ServerSocket.accept() is also a blocking call, which means the loop it's being called in will block (wait) until a user is accepted. This is called Blocking-IO.
All read calls from java.io are blocking.
DataInputStream.readUTF
DataInputStream.readInt
ObjectInputStream.readObject
If you want a system where methods such as these don't block, I suggest looking into the java.nio package (new IO). It far more advanced in my opinion, especially for someone who doesn't have a grasp on basic networking yet, but non-blocking IO's allow for your underlying OS to inform your application when to read/write (through a selector), thus removing the need for blocking calls.
Other than that, there is no way you can prevent readUTF to stop blocking, or somehow skip it without data coming through it.
I need to build a pool of workers in Java where each worker has its own connected socket; when the worker thread runs, it uses the socket but keeps it open to reuse later. We decided on this approach because the overhead associated with creating, connecting, and destroying sockets on an ad-hoc basis required too much overhead, so we need a method by which a pool of workers are pre-initializaed with their socket connection, ready to take on work while keeping the socket resources safe from other threads (sockets are not thread safe), so we need something along these lines...
public class SocketTask implements Runnable {
Socket socket;
public SocketTask(){
//create + connect socket here
}
public void run(){
//use socket here
}
}
On application startup, we want to initialize the workers and, hopefully, the socket connections somehow too...
MyWorkerPool pool = new MyWorkerPool();
for( int i = 0; i < 100; i++)
pool.addWorker( new WorkerThread());
As work is requested by the application, we send tasks to the worker pool for immediate execution...
pool.queueWork( new SocketTask(..));
Updated with Working Code
Based on helpful comments from Gray and jontejj, I've got the following code working...
SocketTask
public class SocketTask implements Runnable {
private String workDetails;
private static final ThreadLocal<Socket> threadLocal =
new ThreadLocal<Socket>(){
#Override
protected Socket initialValue(){
return new Socket();
}
};
public SocketTask(String details){
this.workDetails = details;
}
public void run(){
Socket s = getSocket(); //gets from threadlocal
//send data on socket based on workDetails, etc.
}
public static Socket getSocket(){
return threadLocal.get();
}
}
ExecutorService
ExecutorService threadPool =
Executors.newFixedThreadPool(5, Executors.defaultThreadFactory());
int tasks = 15;
for( int i = 1; i <= tasks; i++){
threadPool.execute(new SocketTask("foobar-" + i));
}
I like this approach for several reasons...
Sockets are local objects (via ThreadLocal) available to the running tasks, eliminating concurrency issues.
Sockets are created once and kept open, reused
when new tasks get queued, eliminating socket object create/destroy overhead.
One idea would be to put the Sockets in a BlockingQueue. Then whenever you need a Socket your threads can take() from the queue and when they are done with the Socket they put() it back on the queue.
public void run() {
Socket socket = socketQueue.take();
try {
// use the socket ...
} finally {
socketQueue.put(socket);
}
}
This has the added benefits:
You can go back to using the ExecutorService code.
You can separate the socket communication from the processing of the results.
You don't need a 1-to-1 correspondence to processing threads and sockets. But the socket communications may be 98% of the work so maybe no gain.
When you are done and your ExecutorService completes, you can shutdown your sockets by just dequeueing them and closing them.
This does add the additional overhead of another BlockingQueue but if you are doing Socket communications, you won't notice it.
we don't believe ThreadFactory addresses our needs ...
I think you could make this work if you used thread-locals. Your thread factory would create a thread that first opens the socket, stores it in a thread-local, then calls the Runnable arg which does all of the work with the socket, dequeuing jobs from the ExecutorService internal queue. Once it is done the arg.run() method would finish and you could get the socket from the thread-local and close it.
Something like the following. It's a bit messy but you should get the idea.
ExecutorService threadPool =
Executors.newFixedThreadPool(10,
new ThreadFactory() {
public Thread newThread(final Runnable r) {
Thread thread = new Thread(new Runnable() {
public void run() {
openSocketAndStoreInThreadLocal();
// our tasks would then get the socket from the thread-local
r.run();
getSocketFromThreadLocalAndCloseIt();
}
});
return thread;
}
}));
So your tasks would implement Runnable and look like:
public SocketWorker implements Runnable {
private final ThreadLocal<Socket> threadLocal;
public SocketWorker(ThreadLocal<Socket> threadLocal) {
this.threadLocal = threadLocal;
}
public void run() {
Socket socket = threadLocal.get();
// use the socket ...
}
}
I think you should use a ThreadLocal
package com.stackoverflow.q16680096;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main
{
public static void main(String[] args)
{
ExecutorService pool = Executors.newCachedThreadPool();
int nrOfConcurrentUsers = 100;
for(int i = 0; i < nrOfConcurrentUsers; i++)
{
pool.submit(new InitSocketTask());
}
// do stuff...
pool.submit(new Task());
}
}
package com.stackoverflow.q16680096;
import java.net.Socket;
public class InitSocketTask implements Runnable
{
public void run()
{
Socket socket = SocketPool.get();
// Do initial setup here
}
}
package com.stackoverflow.q16680096;
import java.net.Socket;
public final class SocketPool
{
private static final ThreadLocal<Socket> SOCKETS = new ThreadLocal<Socket>(){
#Override
protected Socket initialValue()
{
return new Socket(); // Pass in suitable arguments here...
}
};
public static Socket get()
{
return SOCKETS.get();
}
}
package com.stackoverflow.q16680096;
import java.net.Socket;
public class Task implements Runnable
{
public void run()
{
Socket socket = SocketPool.get();
// Do stuff with socket...
}
}
Where each thread gets its own socket.