无法通过通知重新锁定

时间:2017-09-22 20:53:54

标签: java multithreading locking wait notify

我对java线程编码进行了测试,但我有一些基本问题..经过几个小时的尝试和搜索,我决定尝试一下!

我无法理解为什么即使在我的通知之后我的等待仍然被锁定:

在这里你可以找到我的代码:

public class Mymain {

    public static void main(String[] args) {

        for( int i=0;i<100;i++){
            new ThreadClass(i).start();     
        }
    }
}

public class ThreadClass extends Thread {
    static boolean ok = false;
    int id;

    public ThreadClass(int i) {
        id = i;
    }

    public void run() {
        System.out.println("Thread start " + id);
        Last.toDo(id);
        if (id == 5)
            try {
                waiting();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        if (id != 5)
            awaking();

        System.out.println("thread end " + id);
    }

    private synchronized void awaking() {
        // TODO Auto-generated method stub
        if (ok) {
            System.out.println("i'm " + id + " and i'm Awaking 5");
            ok = false;
            notify();
            System.out.println("I did the notify and i'm " + id);
        }
    }

    private synchronized void waiting() throws InterruptedException {
        System.out.println("Sleeping");
        ok = true;
        wait();
        System.out.println("Awake 5");
    }
}

Result

然后它开始循环或它进入死锁不确定..它应该只是停止id = 5的线程然后下一个线程应该重新启动id = 5 ..但线程5永远不会唤醒通知...

在结果中你可以看到我有2个线程试图唤醒线程5并且线程5总是在等待,因为开始^^

4 个答案:

答案 0 :(得分:0)

问题是你没有在你调用wait()的同一个对象上调用notify()。特别是,线程5在自身上调用wait(),但是线程8例如在自身上调用notify(),而不是在线程5上。结果,线程5永远不会得到通知。

此外,您需要创建ok变量volatile以确保在一个线程设置它时,其他线程可以看到更改。在这种特殊情况下,这不会导致您出现问题,但在其他情况下可能会导致问题。

答案 1 :(得分:0)

  

我无法理解为什么即使在我的通知之后我的等待仍然被锁定:

在使用相同的对象实例时等待并通知工作。例如,如果你有:

 String x1 = "...";
 String x2 = "...";

和第1号线做:

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

然后线程#2执行:

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

然后线程#1仍然在等待,因为通知仅适用于x2。在您的示例中,由于您正在使用方法同步,因此ID为5的线程正在等待其自己的ThreadClass实例。然后,当其他线程调用awaking()时,他们也会在ThreadClass的实例上调用notify。如果你想让线程#5看到另一个线程的通知,那么他们应该共享一个锁定对象。

可能是这样的:

 final Object lock = new Object();
 for (int id = 0; id < 100; id++){
        new ThreadClass(id, lock).start();     
 }
 ...
 public class ThreadClass extends Thread {
     private final Object lock;
     ...
     public ThreadClass(int id, Object lock) {
         this.id = id;
         this.lock = lock;
     }
     ...
     private void awaking() {
        ...
        synchronized (lock) {
            lock.notify();
        }
        ...
     }
     private void waiting() throws InterruptedException {
        ...
        synchronized (lock) {
            lock.wait();
        }
        ...
    }
}

答案 2 :(得分:0)

为什么不使用 notifyAll()方法?当您调用notify()时,这意味着只有一个线程会将状态从等待更改为 runnable ,但是当您有多个线程时可能出现这种情况。在线上等待的其他线程,他们将不会收到此通知。在我看来,最好使用notifyAll。

答案 3 :(得分:-1)

看,我对您的代码做了一些更改:

  1. 您不能notify(),您需要通知this。你不能只是wait(),你会永远等待。你必须在Object上使用这些函数,所以我添加了一个Integer对象(只是为了告诉你 - 你必须选择正确的对象)。
  2. 您在synchronizedstatic synchronized之间了解情况。快速搜索将引导您获得完美答案。
  3. 为什么函数waiting()已同步?只有第5号线号称它。
  4. 调用Object.notify() / Object.wait()时,必须在对象上声明一个同步块。
  5. 这里有一些代码:

    public class Threads {
        public static void main(String[] args) {
            Integer intObject = new Integer(0);
            for( int i=0;i<100;i++){
    
                new ThreadClass(i, intObject).start();     
            }
        }
    }
    class ThreadClass extends Thread {
        static boolean ok = false;
        int id;
        Integer intObject;
        public ThreadClass(int i, Integer intObject) {
            id = i;
            this.intObject = intObject;
        }
    
        public void run() {
            System.out.println("Thread start " + id);
            //Last.toDo(id);
            if (id == 5)
                waiting();
            else
                awaking(this);
    
            System.out.println("thread end " + id);
        }
    
        private static synchronized void awaking(ThreadClass t) {
            if(ok) {
                System.out.println("i'm " + t.id + " and i'm Awaking 5");
                ok = false;
                synchronized (t.intObject) {
                        t.intObject.notify();
                    }
                System.out.println("I did the notify and i'm " + t.id);
            }
        }
        private void waiting(){
            System.out.println("Sleeping");
            ok = true;
            synchronized (intObject) {
                try {
                    intObject.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("Awake 5");
        }
    }