我对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");
}
}
然后它开始循环或它进入死锁不确定..它应该只是停止id = 5的线程然后下一个线程应该重新启动id = 5 ..但线程5永远不会唤醒通知...
在结果中你可以看到我有2个线程试图唤醒线程5并且线程5总是在等待,因为开始^^
答案 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)
看,我对您的代码做了一些更改:
notify()
,您需要通知this
。你不能只是wait()
,你会永远等待。你必须在Object上使用这些函数,所以我添加了一个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");
}
}