【问题标题】:Cannot obtain shared variable value in separate threads无法在单独的线程中获取共享变量值
【发布时间】:2010-03-01 04:56:12
【问题描述】:

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

现在,我的主程序实现了几个将全局类中的变量作为共享变量访问的类。

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

    }
}

这只是我用************ 突出显示的部分,我需要帮助弄清楚,为了避免拥挤,我省略了一些不相关的功能。

提前谢谢大家

【问题讨论】:

  • 请正确格式化您的帖子,很难看到这里发生了什么。
  • 你希望任何人都去读那么多代码吗?祝你好运。发布 SSCCE (sscce.org) 以获得更好的答案。
  • 我不了解其他人,但我倾向于实现Runnable,而不是扩展Thread。这样,我可以为我的线程类拥有一个真正的继承层次结构。
  • 哦,对不起,伙计们......我不知道如何简明扼要地解释我的代码......

标签: java multithreading locking global-variables shared


【解决方案1】:

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

【讨论】:

  • 我设法修复了这个错误......我使用了 volatile 关键字,id 使用了同步,然后我在我的主类中将变量 iTimeStamp 声明为公共静态并使用类名访问它在其他类中它仍然不起作用我意识到我的 ServerConnect 类中的 run() 方法正在正确访问该值,但是从 ServerConnect 类中调用的另一个函数 replyChoice 我从上面的代码中遗漏了'没有得到更新的值,并且通过将值作为参数传递给replyChoice函数来修复错误
【解决方案2】:

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

【讨论】:

  • 我设法修复了这个错误......我使用了 volatile 关键字,id 使用了同步,然后我在我的主类中将变量 iTimeStamp 声明为公共静态并使用类名访问它在其他类中它仍然不起作用我意识到我的 ServerConnect 类中的 run() 方法正在正确访问该值,但是从 ServerConnect 类中调用的另一个函数 replyChoice 我从上面的代码中遗漏了'没有得到更新的值,并且通过将值作为参数传递给replyChoice函数来修复错误
【解决方案3】:

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

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

public static Global gb = new Global()

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

【讨论】:

  • 我设法修复了这个错误......我使用了 volatile 关键字,id 使用了同步,然后我在我的主类中将变量 iTimeStamp 声明为公共静态并使用类名访问它在其他类中它仍然不起作用我意识到我的 ServerConnect 类中的 run() 方法正在正确访问该值,但是从 ServerConnect 类中调用的另一个函数 replyChoice 我从上面的代码中遗漏了'没有得到更新的值,并且通过将值作为参数传递给replyChoice函数来修复错误
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-27
  • 1970-01-01
  • 2018-08-28
  • 2021-08-12
  • 2021-08-14
  • 2017-09-10
  • 1970-01-01
相关资源
最近更新 更多