无法通过通知释放锁
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();
}
...
}
}
你看我对你的代码做了一些修改:
- 你不能只
notify()
,你会通知this
。而且你不能只是 wait()
,你会永远等待。您必须在对象上使用这些功能,所以我添加了一个 Integer
对象(只是为了向您展示 - 您必须选择正确的对象)。
- 在
synchronized
和static synchronized
之间,你懂的哟。快速搜索会让您找到完美的答案。
- 为什么函数
waiting()
是同步的?只有线程号 5 调用它。
- 调用
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.
我已经对 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();
}
...
}
}
你看我对你的代码做了一些修改:
- 你不能只
notify()
,你会通知this
。而且你不能只是wait()
,你会永远等待。您必须在对象上使用这些功能,所以我添加了一个Integer
对象(只是为了向您展示 - 您必须选择正确的对象)。 - 在
synchronized
和static synchronized
之间,你懂的哟。快速搜索会让您找到完美的答案。 - 为什么函数
waiting()
是同步的?只有线程号 5 调用它。 - 调用
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.