Не удается получить значение общей переменной в отдельных потоках - PullRequest
0 голосов
/ 01 марта 2010

Моя программа имеет серверный поток и отдельные клиентские потоки, которые являются отдельными подключениями к другим серверам. Итак, как работает моя программа, клиентские потоки делают индивидуальные запросы, и когда каждый из них так, я увеличиваю общую переменную iTimeStamp.

Однако мне нужно получить доступ к значению этой общей переменной через поток моего Сервера, но всякий раз, когда я пытаюсь это сделать, оно не получает обновленное значение, а значение iTimeStamp, к которому осуществляется доступ, всегда равно нулю.

Я только что вставил весь код ниже, я был бы очень признателен, если бы кто-нибудь сказал мне, что мне не хватает, просто чтобы я мог получить доступ к обновленному значению iTimeStamp.

import java.util.Vector;
import java.lang.*;

public class Global {

public static int[] iParameter = new int[8];    

public static Global gb = null;

public static int iTimeStamp;

public static Global getInstance(){
    return gb;
}

Теперь моя основная программа, которая реализует несколько классов, которые обращаются к переменным в классе Global как общие переменные.

class ServerConnect extends Thread {

    Socket skt;
    int iProcessId, iInProcessId;
    int iOwnTimeStamp, iInTimeStamp;
    ServerConnect scnt = null;

    ObjectOutputStream myOutput;
    ObjectInputStream myInput;

    ServerConnect(){}
    ServerConnect(Socket connection, int iProcessNo) {
        this.skt = connection;
        this.iProcessId = iProcessNo;
    }

    public void run() {
        try {

            //initialize the object "scnt" using the parameterized constructor
            ServerConnect scnt = new ServerConnect(skt, iProcessId);
            myInput = new ObjectInputStream(skt.getInputStream());

            while(true) {
                try{

                    Object buf = myInput.readObject();

                    //if we got input, print it out and write a message back to the remote client...
//********************************************************************************
//part where im trying to access the shared variable    
                       //synchronized(Global.xlock){
                    iOwnTimeStamp = Global.getInstance().iTimeStamp;
                                        //}
//***********************************************************************************

                }catch(ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        } catch(IOException e) {
            e.printStackTrace();
        }
    }

class Server extends Thread {

    int iProcessId;
    int iPortNo;

    Server(){}
    Server(int iPName, int iPortNumber){
        this.iProcessId = iPName;
        this.iPortNo = iPortNumber;
    }

    public void run() {
        try{
            //first create a socket & bind it to port 9999
            ServerSocket myServerSocket = new ServerSocket(this.iPortNo);
            while(true) {
                //wait for an incoming connection
                Socket skt = myServerSocket.accept();
                ServerConnect sc = new ServerConnect(skt, iProcessId);
                Thread t = new Thread(sc);//Encapsulating each connection inot a class and running it as a separate Thread

                t.start();
            }
        }catch(IOException ex){
            ex.printStackTrace();
        }
    }
}


class Client extends Thread{
    int iProcessId; 
    String sMessage;
    Socket skt;
    //int iNumReq=0;

    ObjectOutputStream myOutput;
    ObjectInputStream myInput;

    //Constructor that accepts the processId, the corresponding socket and message if any
    Client(int iPid, Socket s, String m) {
        this.iProcessId = iPid;
        this.skt = s;
        this.sMessage = m;
    }

    public void run() {
        try {
            sleep((int)1*8000);
        }catch(Exception e) {}


        try {
            //Creating input and output streams to transfer messages to the server
            myOutput = new ObjectOutputStream(skt.getOutputStream());
            myInput = new ObjectInputStream(skt.getInputStream());

            //ive omitted the part where the client receives the reply from the server

    //sendMessage is called to send messages from the client to the server it is connected to
    void sendMessage(Object msg){
        if(msg!=null){
            try{
                myOutput.writeObject(msg);
                myOutput.flush();
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
}

public class BaseStaInstance extends Thread {

    //variables for every BaseStation instance
    //int iTimeStamp=0;
    int iProcessId;
    Client[] clientList;
    private static BaseStaInstance bs = null;
    Utility u = new Utility();

        //I have the readFile() function implemented here which I have left out 

    //setProcessId()

    //setClientList()

       //getClientList()

    //getIpPort()

    //The connSetUp is used to set up the initial connection between clients and servers
    Client[] connSetUp(int iPid){
        //Broadcast to all processes other than itself
        ArrayList sPortList = u.getPortList(iPid);

        //making a consistency check to ensure the number of stations in the config file is equal to the number specified in the parameter file
        if(sPortList.size()!=(Global.iParameter[1]-1)){
            Global.iParameter[1]=sPortList.size()+1;
            System.out.println("Please note there was an inconsistency in the number of instances specified which was corrected as per the config file");
        }

        //creating the connections from this basestation to the other basestation instances on their ports
        Client[] clientList = new Client[Global.iParameter[1]-1];
        for(int i=0;i<Global.iParameter[1]-1;i++){
            String str = sPortList.get(i).toString();
            int iProcessToConnect = Integer.parseInt(str.substring(0,str.indexOf(",")));
            str = str.substring(str.indexOf(",")+1);
            String sMachineName = str.substring(0, str.indexOf(","));
            int iPortNo = Integer.parseInt(str.substring(str.indexOf(",")+1,str.length()));
            try {
                Socket skt = new Socket(sMachineName, iPortNo);         
                Client client = new Client(iProcessToConnect, skt, null);
                client.start();
                clientList[i] = client;
                try {
                    sleep((int)10000);
                }catch(Exception e){}
            }catch(Exception e){}
        }
        return clientList;
    }


    void broadcastReq(Object message){
        Client[] clientListValue = getClientList();
        for(int i=0;i<clientListValue.length;i++){
            Client client = clientListValue[i];
            client.sendMessage(message);
        }
    }

    void genRequest(){
        //while(true){
            try{
                sleep((int)(new Random().nextInt(50))*100); //The broadcast is done on a random basis
                //i has tried implementing the synchronized function but did not help
                //synchronized(Global.xlock){
                //increment the time stamp on generating the request
//********************************************************************************
//part where im incrementing the iTimeStamp variable.
                Global.getInstance().iTimeStamp++;
//********************************************************************************
                //}

                bs.broadcastReq("Request-BaseStation,"+iProcessId+","+Global.getInstance().iTimeStamp);

            }catch(Exception e){}
        //}
    }

    public static void main(String args[]){
        bs = new BaseStaInstance();

        //read the program parameters file
        bs.readFile();

        int iProcessId = Integer.parseInt(args[0]);
        bs.setProcessId(iProcessId);

        String sIpPort = bs.getIpPort();
        int iServ_port_no = Integer.parseInt(sIpPort.substring(sIpPort.indexOf(",")+1,sIpPort.length()));

        System.out.println("The port number: "+iServ_port_no);

        //Code to Debug---------
        //System.out.println("The Server Port No: "+iServ_port_no);
        //----------------------

        Server serv = new Server(iProcessId, iServ_port_no);
        serv.start();

        try {
            sleep((int)10000);
        }catch(Exception e){}

        Client[] clientList = bs.connSetUp(iProcessId);
        bs.setClientList(clientList);

        bs.genRequest();

    }
}

Это та часть, которую я выделил ************, и мне нужна помощь в выяснении, я опустил некоторые несвязанные функции, чтобы избежать переполнения.

Заранее спасибо, ребята

Ответы [ 3 ]

2 голосов
/ 02 марта 2010

Отдельные переменные, совместно используемые несколькими потоками, должны быть объявлены с ключевым словом volatile. Это гарантирует, что любые записи в эту переменную одним потоком будут немедленно видны всем другим потокам. Без этого потоки могут иметь собственную локальную для потока копию переменной. Возможно, вы захотите использовать один из классов из пакета java.util.concurrent.atomic, например AtomicInteger.

.
2 голосов
/ 02 марта 2010

Попробуйте сделать iTimeStamp volatile или используйте java.util.concurrent.atomic.AtomicInteger

1 голос
/ 02 марта 2010

В конструкторе global вы устанавливаете gb = null. В getInstance () вы возвращаете gb. Нет опубликованного кода, который когда-либо устанавливает gb ​​в любое другое значение. Это приведет к исключениям нулевого указателя .

Попробуйте изменить объявление внутри global на

public static Global gb = new Global()
.

Кроме того, вам следует рассмотреть возможность установки его в private вместо public - если вы не хотите, чтобы другие потоки изменили значение gb на вас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...