无法通过通知释放锁

Can't relase the lock with 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 从一开始就一直在等待^^

问题是您没有在调用 wait() 的同一对象上调用 notify()。特别是,线程 5 在自身上调用 wait(),但是线程 8 在自身上调用 notify(),而不是在线程 5 上。因此,线程 5 永远不会收到通知。

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

i can't understand why my wait is still locked even after my notify :

当使用同一个对象实例时,等待和通知工作。例如,如果您有:

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

线程 #1 执行:

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

然后线程 #2 执行:

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

然后线程 #1 仍将等待,因为通知仅针对 x2。在您的示例中,id 为 5 的线程正在等待它自己的 ThreadClass 实例,因为您正在使用方法同步。然后,当其他线程调用 awaking() 时,它们也会在它们的 ThreadClass 实例上调用通知。如果你想让线程#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();
        }
        ...
    }
}

你看我对你的代码做了一些修改:

  1. 你不能只notify(),你会通知this。而且你不能只是 wait() ,你会永远等待。您必须在对象上使用这些功能,所以我添加了一个 Integer 对象(只是为了向您展示 - 您必须选择正确的对象)。
  2. synchronizedstatic synchronized之间,你懂的哟。快速搜索会让您找到完美的答案。
  3. 为什么函数 waiting() 是同步的?只有线程号 5 调用它。
  4. 调用 Object.notify() / Object.wait() 时,必须在对象上声明一个同步块。

这是一些代码:

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");
    }
}

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