外部调用同步功能保持/锁定

时间:2011-01-17 19:25:40

标签: java multithreading

以下类DoStuff启动一个线程并同步以保护侦听器对象在null时不被访问。

现在,当从外部访问DoStuff类函数setOnProgressListener()时,我遇到了问题,因为调用在退出函数调用之前已经持续了很长时间。我不确定为什么会这样?我好像同步已经排队了很多电话?对此的任何输入都会有所帮助!

我实际上是将null传递给侦听器,因为我不再希望更新此状态。我这样做是杀死​​DoStuff线程的过程的一部分。

谢谢!

public class DoStuff extends Runnable
{
    Object MUTEX = new Object();
    private OnProgressListener mOnProgressListener  = null;

    public DoStuff()
    {
        new Thread(this).start();
    }

    public void setOnProgressListener( OnProgressListener onProgressListener )
    {
        synchronized (MUTEX) 
        {
            mOnProgressListener = onProgressListener;
        }
    }

    private void reportStatus( int statusId )
    {
        synchronized (MUTEX) 
        {
            if (null != mOnStatusListener)
            {
                mOnStatusListener.setStatusMessage(new OnStatusEvent(this, statusId));
            }
        }
    }

    // this is the run of a thread
    public void run()
    {
        int status = 0;
        do
        {
            // do some work and report the current work status
            status = doWork();
            reportStatus( status );
        } while(true);
    }
}

4 个答案:

答案 0 :(得分:2)

您应该使用wait / notify。这是样本;

public class DoStuff {
    Object MUTEX = new Object();
    String data = null;

    public void setData(String data) {
        synchronized (MUTEX) {
            this.data = data;
            System.out.println(Thread.currentThread());
            MUTEX.notifyAll();
        }
    }

    public void run() {
        do {
            synchronized (MUTEX) {
                if (null == data) {
                    return;
                } else {
                    System.out.println(data);
                }
                try {
                    MUTEX.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } while (true);
    }
}

答案 1 :(得分:1)

此代码的问题在于,while()循环在释放监视器后立即尝试抓取监视器MUTEX,甚至yield() - 以帮助调度程序放置另一个线程因此,很有可能其他任何试图获取该监视器的人都会被饿死,因为你的while()循环将消耗大部分CPU时间,即使其他线程可以运行,他们也可能无法获得监视器等着。

理想情况下,应使用wait() / notify()对,或者失败,至少应在Thread.yield()块之外的while循环中调用synchronized。 (但我这第二个“解决方案”真的不是很好的,你应该考虑使用第一个“。”

更新:我再次阅读了代码,我认为我相信您想要实现的目标:每次设置新值时都会打印数据值。如果这是真的,你肯定应该去等待/通知解决方案,尽管如果你想绝对保证打印每一个值,你需要做更多的工作,可能使用队列。

答案 2 :(得分:0)

我对您的代码感到有点困惑,您能提供完整的列表吗?

首先,DoStuff在哪里开始一个线程?如果您的数据仍然为空,为什么要退出? (在setData甚至执行之前,你可能实际上已经脱离了线程。)

但主要的是你在做一个忙碌的等待循环,你可以在互斥上进行同步。这非常浪费,通常会阻塞CPU的内核。

根据您要执行的操作,您可能希望使用等待通知方案,在该方案中,线程会一直处于睡眠状态。

答案 3 :(得分:0)

感谢大家的帮助。我能够确定无限锁的原因。重要且显而易见的是,一旦我运行reportStatus()函数调用,它将保持锁定MUTEX,直到完全执行回调为止。我的错是在注册的回调中我错误地调用了setOnProgressListener(null)。是的,我承认没有发布足够的代码,很可能你们所有人都会抓住这个错误...所以调用setOnProgressListener(null)会等到MUTEX对象被释放,并且reportStatus()被等待等待调用setOnProgressListener(null),因此我陷入了僵局!

我学到的另一个要点是要记住,触发回调消息将一直保持,直到注册的回调函数完成处理它的调用。

全部谢谢!