【问题标题】:Singleton pattern using its methods in different threads单例模式在不同线程中使用其方法
【发布时间】:2011-04-18 13:50:45
【问题描述】:

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

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

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

提前感谢您的努力。

干杯 鲍勃

编辑:

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

【问题讨论】:

  • 您所描述的主线程“中断”的机制尚不清楚。您能否发布一些演示该行为的代码?
  • 想显示一些代码?我相信人们可以更好地帮助你,如果他们不必猜测你如何设置你的类和方法
  • 只有在显式调用interrupt()时才会中断线程。我怀疑您没有这样做,并且您的主线程没有被中断。也许您可以向我们展示一小段代码,以便我们重现问题。
  • 你的主要方法到底在做什么?看起来您在单例上调用的方法不会影响任何类变量等,因此它应该没有副作用,因此您可能不需要同步它。无论如何很难猜到,直到我们有主。另外,对单例使用枚举,否则你以后会遇到问题(如序列化等)。

标签: java multithreading design-patterns singleton


【解决方案1】:

这与单例无关,是吗?您必须同步不应被中断的方法,可能使用synchronized 关键字。这是一个很难完整回答的问题,您可以参考几本书(例如Doug Lea“Java 中的并发编程”)。除此之外,您的问题措辞不够准确,我无法添加更多细节。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • Netbeans 显示有多少线程正在运行,在执行期间,主线程会从一行跳转到另一行完整的行,同一线程没有方法调用。
    • OTOH 我认为拥有线程安全的单例并不坏,至少如果您遵循单例模式则不会。当然,如果你可以不用单例就更好了。
    • @Maverick2k:那么要么你的调试器坏了,要么你正在执行与你正在查看的代码不同的版本(这意味着调试器显示的行实际上并不是正在执行的那个) .
    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-27
      • 1970-01-01
      • 2016-10-17
      • 2019-03-27
      • 1970-01-01
      相关资源
      最近更新 更多