无法在单独的线程中获取共享变量值

时间:2010-03-01 04:56:12

标签: java multithreading locking global-variables shared

我的程序有一个服务器线程和单独的客户端线程,它们是与其他服务器的单独连接。所以我的程序如何工作是客户端线程发出单独的请求,当它们每个都这样时,我增加共享变量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 个答案:

答案 0 :(得分:2)

尝试制作iTimeStamp volatile,或使用java.util.concurrent.atomic.AtomicInteger

答案 1 :(得分:2)

多个线程共享的单个变量应使用volatile关键字声明。这可确保一个线程对该变量的任何写入对所有其他线程立即可见。如果没有这个,线程可能有自己的变量的线程局部副本。您可能还希望使用java.util.concurrent.atomic包中的某个类,例如AtomicInteger

答案 2 :(得分:1)

在global的构造函数中,设置gb = null。在getInstance()中,您将返回gb。没有发布任何代码将gb设置为任何其他值。这将导致空指针异常

尝试将全局内部的声明更改为

public static Global gb = new Global()

此外,您应该考虑将其设置为私有instaead公共 - 除非您希望其他线程更改您的gb值。