【问题标题】:Pass object to thread (access object outside thread)将对象传递给线程(访问线程外的对象)
【发布时间】:2016-12-31 18:03:32
【问题描述】:

我正在做一个简单的服务器-客户端系统。

服务器启动,创建一个只存储信息的对象,然后在收到连接后,创建一个运行线程的新对象。

对于每个线程,我想将第一个对象作为参数传递以更改它(添加/获取信息),但我认为传递它的不是。在尝试我第一次尝试菜单并尝试做一些事情时发现它。

已经看到一些关于这个问题的帖子,但我不知道如何应用到我的代码。

这是服务器代码:

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();
        }

    }
}

会做这些事情的类:

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();
        }

    }



}

当我尝试访问 run() 中的 wk.get 时,我注意到了我的问题,它说找不到对象。

【问题讨论】:

  • 为什么需要 wk 对象? wk 在你的情况下只是 this
  • “扩展线程”是错误的。您的对象不需要扩展 Thread。将其设为 Runnable,将对象传递给构造函数,并将对象赋予线程。在 run() 方法中看到用户提示时,我感到畏缩。
  • 您的构造函数WorkLoad(Socket, Workload) 对其第二个参数没有任何作用。我怀疑这没有达到预期的目的。
  • 是的,这就是我在这里的原因之一,在尝试运行一些查询时发现。
  • @duffymo 我该怎么做才能让用户在运行之外提示?

标签: java multithreading java-threads


【解决方案1】:

这里发生了几件事。

每次获得连接时,您都会创建一个新的 WorkLoad 对象。我认为您希望所有连接都共享您在程序开始时创建的 WorkLoad,但事实并非如此。

第一次连接后,你有两个 WorkLoad 对象:一个是在程序开始时创建的,另一个是你在此处创建的:

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

第二个问题是如何定义 Thread 对象。

  • Thread 已经实现了 Runnable,因此如果您已经有“扩展 Thread”,则不需要“实现 Runnable”。
  • WorkLoad 是一个线程(“扩展线程”),因此您无需将其包装在另一个线程中(“new Thread(new Workload(...))”)。

如果您希望在多个线程之间共享单个 WorkLoad,则需要将 WorkLoad(其中只有一个)的概念与线程(您将拥有多个)的概念分开。

  • 不要让 WorkLoad 扩展 Thread 或实现 Runnable。移除 Socket 成员。
  • 创建一个新类(Worker?),它实现了 Runnable 并具有 Socket 成员。

当您获得新连接时,请执行以下操作:

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

【讨论】:

  • 好的,按照您的建议进行了更改,效果非常好:)
  • 接下来你会遇到线程问题。最好的办法可能是让 WorkLoad 的所有成员“同步”,这样多个线程就不能同时更新数据。
  • 同步够了吗?我打算在更新/设置的方法中创建 locks()
【解决方案2】:

好的....您的代码中有很多问题。

  1. wk 永远不会保存在本地。所以后面的代码无法读取 线程已启动
  2. 类是 Thread 的子类并实现 可运行。这是完全错误的。您可以扩展 Thread 或 实施 Runnable 以有效地做到这一点。

所以我的建议是; 将构造函数更改为

  Workload(Socket socket) {
    this.clientes = 0; this.leiloes = 0 ; this.tid = 0;
    this.socket = socket;
  }

无需创建一个 Workload 对象并将其传递给另一个 Workload 对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-16
    • 1970-01-01
    相关资源
    最近更新 更多