简单的单向挂起线程

时间:2015-10-22 13:28:11

标签: java multithreading

我有一个小项目,我有2个帖子ListenerThreadHeartbeatThread,它们都是HeartbeatServer内的嵌套类。

我所拥有的是当有人发送请求时,监听器线程将客户端添加到registerClients(其余部分超出了此问题的范围)。

我正在寻找一种在HeartbeatThread hashmap中没有客户端时暂停registerClients的简单方法。

最初我认为它会像在ListenerThread中使用while循环顶部的if语句一样容易,它会检查有多少客户端,如果客户端数量小于零ListenerThread当客户端数量大约为零时,1}}会调用heartbeatServer.heartbeatThread.wait()heartbeatServer.heartbeatThread.notify()。但是当我这样做时,java会抛出一个IllegalMonitorException。在进行了一些挖掘后,我发现异常是因为我没有在wait()块内调用synchronized

因为我期待只走一条路ListenerThread -> HeartbeatThread而从来没有别的方法我怎么能做到这一点?在每个帖子中使用synchronized块时,我还会更好吗?如果是这种情况,那么我需要澄清一下我正在同步的是什么。

我找到了这个例子;

boolean ready = false;

// thread 1
synchronized(lock) {
    ready = true;
lock.notifyAll();
}


// thread 2
synchronized(lock) {
    while(!ready) 
        lock.wait();
}

这个例子看起来会解决我的问题。但由于我是新手,我不确定lock应该是什么。

可以重新设计或完成示例以满足我的需求,还是有更好的方法来解决我的问题?

我不确定需要显示哪些代码,以便发布所需的任何内容。

更新

我想我终于找到了解决问题的方法。     公共类HeartbeatServer {

final Object lock = new Object();
volatile Boolean suspended = true;

//TEST USE ONLY
volatile int userCount = 0;

// This is the thread that will send the heartbeats back to the client.
private class HeartbeatThread implements Runnable {

    @Override
    public void run() {

        HeartbeatServer heartbeatServer = HeartbeatServer.getInstance();

        while (true) {

            synchronized (heartbeatServer.lock) {

                if(suspended) {

                    try {

                        System.out.println("Suspending heartbeat thread!");
                        heartbeatServer.lock.wait();

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                } else {

                    System.out.println("Resuming heartbeat thread!");

                } // End if block

            } // End synchronized block

            try {

                Thread.sleep(2000L);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        } // End while loop

    } // End run method

} // End HeartbeatThread

// This is the thread that will listen for clients connecting to the server.
private class ListenerThread implements Runnable {

    // The instance of heartbeatServer should be the first object so we can use it everywhere in the class.
    HeartbeatServer heartbeatServer = HeartbeatServer.getInstance();

    private void suspendHeartbeats() {

        synchronized (heartbeatServer.lock) {

            heartbeatServer.suspended = true;

        }

    } // End suspendHeartbeats

    private void resumeHeartbeats() {

        synchronized (heartbeatServer.lock) {

            heartbeatServer.suspended = false;
            heartbeatServer.lock.notify();

        }

    } // End resumeHeartbeats

    @Override
    public void run() {

        while(true) {

            if(heartbeatServer.userCount < 1) {

                suspendHeartbeats();

            } else {

                resumeHeartbeats();

            }

        } // End while loop

    } // End run method

} // End ListenerThread

} // End HeartbeatServer

我还能做些什么来改善我的线程吗? HeartbeatThread中的一些部分是在测试中遗留下来的。但我更多地提到用于暂停HeartbeatThread的逻辑。

1 个答案:

答案 0 :(得分:2)

你听起来已经找到了你需要的核心,只是信心阻挡你。 wait / notify是Java中相当低级的原语,并且在使用它们时会出现一个微妙的时序错误。这就是为什么存在像ReadWriteLock,Semaphore等更高级别的抽象的原因。 Java API文档中有一个示例演示了如何阻止直到达到条件(例如空或满)here,他们使用ReentrantLock和Condition来表示空/非空。

回到你关于锁对象的问题,它只是他们正在调用wait / notify的对象。它可以或多或少是任何对象,只要它始终是同一个对象。

有一个论点说当使用synchronized / wait / notify时,应该使用私有的最终对象而不是公开的对象。参数是,如果锁定对象被暴露,那么其他代码本身可以调用wait / notify / synchronized来对其进行调整并产生副作用,这可能会变得难以追踪。无论如何,线程代码很难,所以这个论点的目的是减少外部干扰蔓延的机会。这解释了你的例子,因为它符合这个惯例。