单例模式在不同的线程中使用其方法

时间:2011-04-18 13:50:46

标签: java multithreading design-patterns singleton

在设计可由多个线程使用的单例类时,我遇到了以下挑战:

退出主线程和另一个称为客户端的线程。主要方法首先获取一个实例,然后客户端也获取实例。然后客户端执行单例类的方法,我的调试步骤向我显示主线程被中断以执行客户端调用的方法。

如何确保客户端线程执行该方法,而不会中断主线程。

提前感谢您的努力。

干杯 鲍勃

编辑:

public class SingletonEsperEngine {

    private static SingletonEsperEngine esperEngineObject;
    //Configuration for the Esper Engine
    private static Configuration cepConfig;
    //EPSServiceProvider represents the engine instance
    private static EPServiceProvider cep;
    private static EPRuntime cepRT;
    private static EPAdministrator cepAdm;
    private static boolean IsAlreadyInitialized;
    private static boolean IsNodeIdAvailable;
    public static ArrayList<EPStatement> cepStatement;
    public static ArrayList<EPStatement> cepLogInfo;
    public static ArrayList<EPStatement> cepFilterStatement;
    public static HashMap<String, Integer> mStatistics;
    public static HashMap<Integer, Integer> mNodeIds;


    //Experiment instantions
    private static JoinDebug joinDebugExperiment;



    private SingletonEsperEngine() {
    }

    /**
     * In order to prevent simultaneous invocation of the getter method
     * by 2 threads or more, we add the synchronized keyword to the method
     * declaration.
     *
     * @return SingletonEsperEngine
     */
    public static synchronized SingletonEsperEngine getInstance() {
        if (esperEngineObject == null) {
            esperEngineObject = new SingletonEsperEngine();
            IsAlreadyInitialized = false;
            IsNodeIdAvailable = false;
        }

        return esperEngineObject;
    }

    /**
     * InitEsperService
     *
     * Initialize the Esper Engine to accept MyriaNed messages.
     *
     * @return
     */
    public static synchronized int InitEsperService() {

    }

public int dataToEsperEngine(String data, int numOfClient) {
        //Split string into timestamp and Myrianed Message 32 bytes
        String strTimestampClientSec = data.substring(0, 16);
        String strTimestampClientNano = data.substring(16, 32);
        String strTimestampSniffer = data.substring(32, 40);
        String message = data.substring(40);
        String joinBitMask = CONSTANT.JOIN_MESSAGE_bm.substring(2, 4) + CONSTANT.JOIN_MESSAGE_bm.substring(0, 2);

        HashMap<String, Object> Event = new HashMap<String, Object>();

            //It is an join message

            Event = putDataIntoEvent(message, evaluationMsgStruct, stamp, numOfClient);
            cepRT.sendEvent(Event, CONSTANT.JOIN_MESSAGE)

        if (CONSTANT.DEBUG) {
            printEventHashMap(Event, evaluationMsgStruct);
        }

        return CONSTANT.SUCCESS;
    }

当客户端线程调用dataToEsperEngine()

时会导致问题
public class Client implements Runnable {

    Socket mClientConnectionSocket;
    Connection mCon;
    //Seperate thread for every client, to handle the communication and event processing
    //ClientThread clientThread;
    public static Boolean stopClientThreads = false;
    public int mMode = CONSTANT.CLIENT_MODE_IDLE;
    public int mNumberOfThisClient;
    SingletonEsperEngine mEsperSupport;
    public Thread t;
    private String name;



    public void run() {
        String tmp = null;
        int idleTime = CONSTANT.SHORT_IDLE_TIME;

        while (!stopClientThreads) {
            try {
                tmp = null;
                switch (mMode) {
                    case CONSTANT.CLIENT_MODE_STOP:
                        //This will cause exiting of the while loop and terminates the thread
                        stopClientThreads = true;
                        return;
                    case CONSTANT.CLIENT_MODE_IDLE:
                        //Being lazy
                        break;
                    case CONSTANT.CLIENT_MODE_RECEIVE_STREAM:
                        tmp = receiveMessage();
                        if (tmp != null) {
                            System.out.println(tmp);
                            mEsperSupport.dataToEsperEngine(tmp, mNumberOfThisClient);
                        }
                        break;
                }

                //I am aware of the performance issues
                //TODO rebuild with execution pool
                this.t.sleep(idleTime);

            } catch (InterruptedException ex) {
                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
        return;
    }

    Client(Socket cC, String name) {
        //Save socket (=connection) into the client class
        mClientConnectionSocket = cC;
        gui.Debug.logThis("The server made a connection with: " + mClientConnectionSocket.getInetAddress());

        mEsperSupport = mEsperSupport.getInstance();

        this.name = name;
        mMode = CONSTANT.CLIENT_MODE_IDLE;

        t = new Thread(this);
        t.start();

        this.mNumberOfThisClient = Integer.parseInt(name);

        //Connect the input and output stream
        try {
            mCon = new Connection(new BufferedReader(new InputStreamReader(mClientConnectionSocket.getInputStream())), new PrintWriter(mClientConnectionSocket.getOutputStream()));
        } catch (IOException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }




    }

    public String receiveMessage() {
        String tmp = null;
        try {
            tmp = mCon.cFrom.readLine();
        } catch (IOException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }

        return tmp;
    }
}

3 个答案:

答案 0 :(得分:6)

这与单身人士无关,是吗?您必须使用synchronized关键字来同步不会中断的方法。这是一个难以回答的问题,有几本书(例如 Doug Lea 'Java并行编程')你可以参考。除此之外,你的问题并没有足够精确地让我添加更多细节。

答案 1 :(得分:2)

  

然后客户端执行一个方法   单例类我的调试步骤   通过向我展示主线程   被中断以执行该方法   这是由客户调用的。

这是绝对不可能的(除非你的主线程和单例类都包含一些相当复杂的代码来强迫tham这样做,在这种情况下,解决方案当然不是以这种方式实现它们)。很可能你错误​​地解释了调试器显示的内容。

答案 2 :(得分:0)

可以这样做但你只在“关键部分”,“关键数据”上进行同步。因为,我没有在你的代码中看到任何关键部分,我不认为你真的需要在客户端和主线程之间进行同步。也许这条线可以被视为关键部分:

Event = putDataIntoEvent(message, evaluationMsgStruct, stamp, numOfClient);

但是根据你提供的来源,很难这么说。