Search code examples
javamultithreadingjava-threads

Pass object to thread (access object outside thread)


I'm doing a simple server-client system.

the server starts, creates an object that will only store info, then after it receives a connection, creates a new object that runs a thread.

For every thread i want to pass the first object as a param to alter it (add/get info) but what i thought was passing it on, is not. Discovered it on tried my first atempt to a menu and try to do stuff.

Already saw some posts regardings this issue but i couldn't figure it out how to apply to my code.

Here is the server code:

import java.io.*;
import java.net.*;
import java.net.*;

public class Servidor {

    static final int PORT = 8000;

    public static void main(String args[]) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        int i = 0;

        //the object that will only store info
        WorkLoad wk;
        wk = new WorkLoad();

        try {
            serverSocket = new ServerSocket(PORT);
            System.out.println("Leiloes do Ave 2097");
        } catch (IOException e) {
            e.printStackTrace();

        }
        while (true) {
            try {
                socket = serverSocket.accept();
            } catch (IOException e) {
                System.out.println("I/O error: " + e);
            }
            // new thread passing the previously created object
            //new WorkLoad(socket, wk).start();
            Thread t = new Thread(new WorkLoad(socket, wk));
            t.start();
        }

    }
}

The class that will do the stuff:

import java.net.*;
import java.util.*;
import java.io.*;
import java.lang.*;


public class WorkLoad extends Thread implements Runnable {
    protected Socket socket;
    //private int y; //usado no menu?
    private int clientes;
    private int leiloes;
    private int tid; //thread id
    private HashMap<Integer,Cliente> lClientes; //lista de todos os clientes existentes <ID,Cliente()>
    private HashMap<Integer,Leilao> lLeiloes; //lista de todos os leilões existents <ID, Leilao()>
    private HashMap<Integer,String> lThreads; //lista das threads
    private String[] menu = new String[10];
   // the construtor of the object to store info
    public WorkLoad() { this.clientes = 0; this.leiloes = 0 ; this.tid = 0;} //fazer sempre ++ ao criar
    // and here what i thought would pass the object to the thread, the thread constructor
    public WorkLoad(Socket clientSocket, WorkLoad wk) {
        this.socket = clientSocket;
        //this.tid = id;
        //wk.addTid(id,"");
    }

    public HashMap<Integer,Cliente> getListaClientes() { return this.lClientes; }
    public HashMap<Integer,Leilao> getListaLeiloes() { return this.lLeiloes; }
    public void addCliente(Integer id, Cliente c) { this.lClientes.put(id,c); }
    public void addLeilao(Integer id, Leilao l) { this.lLeiloes.put(id,l); }
    public int getTotalLeiloes() { return this.leiloes; }
    public int getTotalClientes() { return this.clientes; }
    public void addTid(int id,String s) { lThreads.put(id,s); } //adiciona thread lista
    public int getTid() { return this.tid; }
    public String getTidMsg(int id) { return lThreads.get(id);} //devolve mensagem da lista de threads
    public Leilao getLeilao(Integer id) { return this.lLeiloes.get(id); } //devolve o leilao pela id



    public void run() {

        PrintWriter out = null;
        BufferedReader in = null;
        DataOutputStream cout = null;
       //private HashMap<Integer,String> lThreads;
        //MENU
        menu[0] = "1"; //menu de escolha menu[0] = MENU.A.APRESENTAR
        menu[1] = "- Registo de utilizador - :insere o username e depois a password\n"; //tem de fazer 2 readlines
        menu[2] = "- Login de utilizador - :insere o username e depois a password\n"; //tem de fazer 2 readlines
        menu[3] = "- Menu geral - :1)Criar Leilao:2)Listar Leiloes:3)Licitar leilao:4)Terminar Leilao:Para sair escreva exit\n";
        menu[4] = "- Licitar leilao - :Insere o id de leilao e depois o valor da tua licitação com . (ex 5.5)\n"; //tem de fazer 2 readlines
        menu[5] = "- Criar leilao - :Insere a descricao do item\n";
        menu[6] = "- Terminar Leilao -:Insere a id do leilao que queres terminar\n";


        try {
            //System.out.println(socket.getInetAddress() + " entrou.");
            //ArrayList<String>
            out = new PrintWriter(socket.getOutputStream());
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //v2
            cout = new DataOutputStream(socket.getOutputStream());            
            cout.writeBytes("Bem vindo ao leilões do Ave :1) Registo :2) login :exit para sair.\n");

            String input;
            //cria nova instancia de cliente
            Cliente clithread = new Cliente(wk.getTotalClientes());

             //while((input = in.readLine()) != null) {
             while(true) {
                input = in.readLine(); //Lê uma linha - tem de se tratar linha a linha
                if(input.equals("exit")) { in.close(); cout.close(); socket.close(); return; }
                if(input.equals("1")) { } // registo cliente
                //cout.writeBytes(menu[input.toString()]); //print menu registo
                //input = in.readLine(); //lê username
                //cout.writeBytes("Recebi a mensagem:" + input + "\n"); //POR O \n no fim ou o cliente nao funciona direito!!
                //System.out.println(input); //print no server local
             }

           // in.close();
           // out.close();
          //  socket.close();

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }



}

I noticed my problem when i was trying to access the wk.get inside the run() and it was saying it could not find the object.


Solution

  • There are a couple of things going on here.

    You're creating a new WorkLoad object every time you get a connection. I think that you want all of the connections to share the WorkLoad you're creating at the start of the program, but that's not what's happening.

    After the first connection, you have two WorkLoad objects: the one created at the start of the program, and the one you created here:

    Thread t = new Thread(new WorkLoad(socket, wk));
    

    The second issue is how you're defining your Thread object.

    • Thread already implements Runnable, so you don't need "implements Runnable" if you already have "extends Thread."
    • WorkLoad is a Thread ("extends Thread") so you don't need to wrap it in another thread ("new Thread(new Workload(...))").

    If you want a single WorkLoad shared among multiple threads, you need to separate the concept of WorkLoad (of which there is only one) from the concept of a thread (of which you will have multiple).

    • Don't have WorkLoad extend Thread or implement Runnable. Remove the Socket member.
    • Create a new class (Worker?) that does implement Runnable and that has the Socket member.

    When you get a new connection, do something like:

    Thread t = new Thread(new Worker(socket, wk));
    t.start();