前言:
从java 1.0开始,java中的每一个对象都有一个内部锁。如果一个方法使用synchronized关键字声明,那么对象的锁将保护整个方法。也就是说,要调用该方法,线程必须获得对象的内部锁。
内部的对象锁只有一个相关条件。wait方法添加一个线程到等待集中,notifyAll/notify方法解除等待线程的阻塞状态。换句话说,等价于 intrinsicCondition.await() intrinsicCondition.signalAll()。
一、将方法声明为synchronized
public synchronized void method(){
//to do something
}
可以看到, 使用 synchronized 关键字来编写代码要简洁得多。当然,要理解这一代码,你 必须了解每一个对象有一个内部锁, 并且该锁有一个内部条件。由锁来管理那些试图进入 synchronized 方法的线程,由条件来管理那些调用 wait 的线程。
二、将静态方法声明为 synchronized
如果调用这种方法,该方法获得相关的类对 象的内部锁。例如,如果 Bank 类有一个静态同步的方法,那么当该方法被调用时,Bank.class 对象的锁被锁住。因此,没有其他线程可以调用同一个类的这个或任何其他的同步静态方法。
三、同步阻塞
正如刚刚讨论的,每一个 Java 对象有一个锁。线程可以通过调用同步方法获得锁。还有另一种机制可以获得锁,通过进入一个同步阻塞。当线程进入如下形式的阻塞:于是它获得 Obj 的锁
synchronized (obj)
// this is the syntax for a synchronized block {
critical section
}
例子- 使用thread2唤醒thread1
package com.java.future;
/**
* wait()等待 notify()唤醒
* @author Administrator
*
*/
public class WaitAndNotify{
private Object lock = new Object();
public void method1() throws InterruptedException{
synchronized (lock) {
lock.wait();//当前线程获得lock对象锁后才能使用 wait() ,让当前线程挂起等待,知道被释放
System.out.println(Thread.currentThread().getName() +" method1");
}
}
public void method2() throws InterruptedException{
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " method2");
lock.notify(); //唤醒一个正在等待这个lock对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;
}
}
public static void main(String[] args) {
final WaitAndNotify m = new WaitAndNotify();
Thread t =new Thread(new Runnable() {
@Override
public void run() {
try {
m.method1();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Thread t2 =new Thread(new Runnable() {
@Override
public void run() {
try {
m.method2();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
t.start();
t2.start();
}
}
四、局限性
1.内部锁和条件存在一些局限。包括:
- 不能中断一个正在试图获得锁的线程。
- 试图获得锁时不能设定超时。
- 每个锁仅有单一的条件, 可能是不够的。
2.在代码中应该使用哪一种? Lock 和 Condition 对象还是同步方法?下面是一些建议:
- 最好既不使用 Lock/Condition 也不使用 synchronized 关键字。在许多情况下你可以使 用 java.util.concurrent 包中的一种机制,它会为你处理所有的加锁。例如,使用阻塞队列来同步完成一个共同任务的线程。还应当研究一下并行流。
- 如果 synchronized 关键字适合你的程序, 那么请尽量使用它,这样可以减少编写的代 码数量,减少出错的几率。
- 如果特别需要 Lock/Condition 结构提供的独有特性时,才使用 Lock/Condition。
参考: Java核心技术 卷1(第9版)