synchronized的使用:
(1)synchronized(obj){}的使用
obj是一个实例对象,可以是任意对象,当在多线程中通过各种方式执行到该synchronized包围的代码段,需要先拿到obj对象的锁才能继续往后执行,否则就阻塞,阻塞的时候一直判断有没有拿到obj的锁,如果拿到obj的锁了,就可以继续执行,如果还没拿到obj的锁,继续阻塞。
(2)synchronized用在实例方法(或者叫做动态方法)上
相当于(1)中所说的
synchronized(this){
//实例方法的代码放在这...
}
(3)synchronized用在静态方法上
假设该静态方法属于A类,则相当于(1)中所说的
synchronized(A.class){
静态方法的代码放在这...
}
Object中wait、notify、notifyAll方法的使用
正常使用这三个方法的前提:这三个方法的使用必须在同步代码块中,并且该同步代码块的对象锁是这几个方法所属的对象的对象锁。否则报非法监视器异常(IllegalMonitorStateException)。具体看下面代码:
//下面synchronized的参数如果是lock对象,则在该同步代码块内只能调用lock对象的wait、notify、notifyAll方法
synchronized (lock) {
try {
lock.wait();
// lock.notify();
// lock.notifyAll();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
为什么要这样呢?因为释放锁与获得的锁都要是同一个锁才能保证同步。
synchronized一开始是获得lock对象的锁,那么只有调用lock对象的wait方法才能保证这个时候wait方法释放的是同一把锁。
用反例来说明:
首先,wait方法的作用是释放对象锁,然后阻塞当前线程(也就是当前线程跑到阻塞队列中了)。
当调用的是其他对象的wait方法时,不会释放lock的对象锁,而当前线程却又跑到阻塞队列中了,那么lock对象锁还是一直被当前线程把持着----------也就是说,当前线程被阻塞了,却还持有lock的对象锁,这就会导致其它线程无法再获得lock的对象锁,然后导致死锁。
1、wait的使用
前面的例子中其实就是用wait作为讲解,这里不再赘述。
2.notify的使用
唤醒该notify()方法所属对象的等待集中随机一个线程,被唤醒的线程处于可运行状态,即此时该线程可以和其他线程一起竞争锁了。
但是,需要注意,调用notify时,所属同步代码块是不会立即释放锁的,而是在该代码块执行完之后释放锁,也就是说,被唤醒的线程还是要等当前调用notify的线程中的同步代码块执行完才能开始竞争,否则只能等着。不懂的话,看下面的截图
3.notifyAll的使用
与notify类似,只不过是唤醒该notifyAll方法所属对象的等待集中的所有线程,其他就与notify一样了。