以下类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);
}
}
答案 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),因此我陷入了僵局!
我学到的另一个要点是要记住,触发回调消息将一直保持,直到注册的回调函数完成处理它的调用。
全部谢谢!