Подтвердить что ты не робот

Java.lang.IllegalMonitorStateException: объект не заблокирован потоком перед wait()?

Я использую диалог прогресса. Мне нужно остановить поток, когда пользователь закрывает progressdialog. К сожалению, он дает исключение, помогите мне...

В внутреннем классе

class UpdateThread extends Thread{

    public  void run() {
        while (true){
            count=adapter.getCount();

            try {
               mHandler.post(  new Runnable() {
                    public  void run() {
                        Log.i(TAG,count+"count");
                        progressDialog.setMessage(count + "Device  found");
                    }
                });
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Oncreate

 updateThread=new UpdateThread();

 progressDialog= new ProgressDialog(GroupListActivity.this);
 synchronized (this) {
     updateThread.start();
 }

ondismissal

   progressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
        @Override
        public  void onDismiss(DialogInterface dialog) {
            try {
                synchronized (this) {
                    updateThread.wait(300);
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.i(TAG,"Thread is stopped");
        }
    });
4b9b3361

Ответ 1

Это неправильно:

synchronized(foo) {
    foo.wait();
}

Проблема в том, что будет пробуждать эту тему? То есть, как вы гарантируете, что другой поток не вызовет foo.notify(), прежде чем первый поток вызовет foo.wait()? Это важно, потому что объект foo не будет помнить, что он был уведомлен о том, что сначала будет вызван вызов уведомления. Если есть только одно уведомление(), и если это произойдет до wait(), то wait() никогда не вернется.

Здесь, как предполагалось использовать wait и notify:

private Queue<Product> q = ...;
private Object lock = new Object();

void produceSomething(...) {
    Product p = reallyProduceSomething();
    synchronized(lock) {
        q.add(p);
        lock.notify();
    }
}

void consumeSomething(...) {
    Product p = null;
    synchronized(lock) {
        while (q.peek() == null) {
            lock.wait();
        }
        p = q.remove();
    }
    reallyConsume(p);
}

В этом примере наиболее важными являются то, что существует явный тест для условия (т.е. q.peek()!= null), и что никто не изменяет условие без блокировки блокировки.

Если потребитель вызывается первым, тогда он найдет очередь пустой и будет ждать. Не может быть момента, когда производитель может проскользнуть, добавить Продукт в очередь и затем уведомить блокировку, пока потребитель не будет готов принять это уведомление.

С другой стороны, если производитель сначала вызывается, то пользователю гарантированно не называть wait().

Цикл в потребителе важен по двум причинам: во-первых, если есть более одного потребительского потока, то один потребитель может получать уведомление, но затем другой потребитель пробирается и крадет Продукт из очередь. Единственная разумная вещь для кулачного потребителя в этом случае - снова подождать для следующего Продукта. Другая причина, по которой этот цикл важен, заключается в том, что Javadoc говорит, что Object.wait() разрешено возвращать, даже когда объект не был уведомлен. Это называется "ложным пробуждением", и правильный способ справиться с ним - вернуться и снова подождать.

Также обратите внимание: блокировка private и очередь private. Это гарантирует, что никакая другая единица компиляции не будет вмешиваться в синхронизацию в этом модуле компиляции.

И обратите внимание: блокировка - это другой объект из самой очереди. Это гарантирует, что синхронизация в этом модуле компиляции не будет мешать любой синхронизации, выполняемой реализацией Queue (если есть).


ПРИМЕЧАНИЕ. В моем примере повторно изобретено колесо, чтобы доказать точку. В реальном коде вы должны использовать методы put() и take() для ArrayBlockingQueue, которые будут заботиться обо всем ожидании и уведомлении для вас.

Ответ 2

Вы можете ждать только объекта, если у вас уже есть блокировка, вы можете попробовать:

synchronized (updateThread) {
    updateThread.wait(300);
}

... но я не совсем уверен, чего вы пытаетесь достичь с помощью замков.

Ответ 3

Похоже, вы пытаетесь использовать synchronized и wait, где вы не должны быть.

Если вы действительно хотите дождаться окончания потока, вы должны сделать что-то вроде этого

В UpdateThread:

class UpdateThread extends Thread{
    public AtomicBoolean stopped = new AtomicBoolean(false);
    public  void run() {
        while (!stopped.get()){
    .....

В твоем создании:

updateThread = new UpdateThread();
progressDialog = new ProgressDialog(GroupListActivity.this);
updateThread.start();    // no synchronization necessary

В вашем объявлении:

progressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
        @Override
        public  void onDismiss(DialogInterface dialog) {
            try {
                updateThread.stopped.set(true);
                updateThread.join(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.i(TAG,"Thread is stopped");
        }
    });

Заметьте, я добавил условие завершения к вашему потоку, чтобы он фактически остановился (как и ваш поток будет продолжаться). Вероятно, вы захотите сделать условие выхода частным и добавить сеттер для чистоты. Кроме того, я использую join, чтобы дождаться завершения вашего потока.