!!!!!!!!!!........................................
这三个东西,很容易,也很容易理解,几句话就轻松搞定了。
synchronized : 同一时刻只能有一个对象持有锁!
wait() : 当前线程会进入阻塞状态,并放弃锁
notify() :则会叫醒某一个线程
notifyAll():会叫醒所有线程
可是上面的理解对吗?
至少最后两个是错的。我原以为自己掌握的还好,可是今天遇到的这些状况却让我
不能自信的作出解释。
先看synchronized:
看下面这个例子,如果直接像下面一样通过一个SynTest对象调用,那么start这个锁就跟没加一样!
其实这个原因很简单,加锁的对象只能在一处使用,不管你是不是加锁对象本身,t1就是那个加锁的对象,它拥有那个锁,你可以无限的
调用它的加锁方法。
public class SynTest {
public static void main(String[] args) {
SynTest t1 = new SynTest();
for(int i = 0 ; i < 10; i++) {
A a = t1.create();
t1.start(a);
}
}
A create() {
A a = new A();
return a;
}
class A implements Runnable {
// SynTest t ;
@Override
public void run() {
test();
// t.test(); (这里test加了synchronized)
}
// A(SynTest t) {
// this.t = t;
// }
}
public void test () {
System.out.println(this);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void start(Runnable a) {
new Thread(a).start();
}
}
在看wait()和notify() / notifyAll() :
这两个东西我是误区颇深啊!
就像下面的代码,我还在一直想着,最后能够把所有的线程都唤醒了..
public class Test {
public static void main(String[] args) throws InterruptedException {
init();
while(!conns.isEmpty()) {
Conn conn = conns.remove(0);
conn.start();
Thread.sleep(100);
}
}
static List<Conn> conns = new ArrayList<Conn> ();
static void init() {
conns.add(new Conn());
conns.add(new Conn());
conns.add(new Conn());
}
static class Conn extends Thread {
@Override
public void run() {
try {
send();
response();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " get response" );
}
public synchronized void send() throws InterruptedException {
if(!conns.isEmpty()) {
System.out.println(Thread.currentThread().getName() + " send A to Server");
wait();
} else {
response();
}
}
public synchronized void response() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
notifyAll();
}
}
}
首先第一点,这两个东西必须方法在同步代码中,你可以给方法加synchronized 或者给 代码块加!
然后就是notify/notifyAll , 不是 A.notify() 或者 A.notifyAll() 就会把 B线程唤醒!!!!!
它是与对象挂钩,那个对象notify就只能notify那些等待这个对象控制权的线程!!!!
如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。
关于notify()/notifyAll()还要注意下下面这种情形:
当调用完了notify() / notifyAll() 的时候,并不等于等待线程就会立马运行,只有等调用完notify()或者notifyAll()
并退出synchronized块,释放对象锁后,其余线程才可获得锁执行。就像下面的例子,虽然调用了notifyAll()可是
线程阻塞在了,只有等他醒来,等待线程才能重新获得锁。
synchronized (flag) {
flag = "true";
flag.notifyAll();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
这篇博客 : notify / notifyAll / wait