synchronized几种用法 每个Java对象都可以用做一个实现同步的互斥锁,这些锁被称为内置锁。线程进入同步代码块或方法时自动获得内置锁,退出同步代码块或方法时自动释放该内置锁。
- 实例同步方法
synchronized用于修饰实例方法(非静态方法)时,执行该方法需要获得的是该类实例对象的内置锁(同一个类的不同实例拥有不同的内置锁)。如果多个实例方法都被synchronized修饰,则当多个线程调用同一实例的不同同步方法(或者同一方法)时,需要竞争锁。但当调用的是不同实例的方法时,并不需要竞争锁。
- 静态同步方法
synchronized用于修饰静态方法时,执行该方法需要获得的是该类的class对象的内置锁(一个类只有唯一一个class对象)。调用同一个类的不同静态同步方法时会产生锁竞争。
- 同步代码块
synchronized用于修饰代码块时,进入同步代码块需要获得synchronized关键字后面括号内的对象(可以是实例对象也可以是class对象)的内置锁。
需要注意的是,Class对象的内置锁和实例对象的内置锁不是同一个,两者之间不产生竞争。
public static void main(String[] args) {
SynchronizeClass syncObj = new SynchronizeClass();
new Thread(() -> syncObj.syncMethod("t1")).start();
new Thread(() -> syncObj.syncMethod2("t2")).start();
new Thread(() -> SynchronizeClass.staticSyncMethod("static t3")).start();
new Thread(() -> SynchronizeClass.staticSyncMethod2("static t4")).start();
}
public class SynchronizeClass {
public static int sleepTime = 3*1000;
// syncMethod 和 syncMethod2 都是同步实例方法,会产生竞争
public synchronized void syncMethod(String s) {
sleep(s);
}
public synchronized void syncMethod2(String s) {
sleep(s);
}
// staticSyncMethod 和 staticSyncMethod2 都是同步静态方法,会产生竞争
public static synchronized void staticSyncMethod(String s) {
sleep(s);
}
public static synchronized void staticSyncMethod2(String s) {
sleep(s);
}
private static void sleep(String msg) {
System.out.println(msg);
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出:
t1
static t3
... // 3s后
t2
static t4
通过输出可以看出,同步实例方法之间会产生竞争,同步静态方法之间会产生竞争,但是同步实例和同步静态方法不会竞争。
- wait:
wait方法是Object类的方法。
在一个线程中调用Object.wait()时,该线程将会等待,并释放持有的锁。直到其他线程调用同一个对象的notify()或notifyAll(),休眠的线程才会被唤醒。
但是,线程唤醒并不等于线程可以立马往下执行,还需要唤醒的线程获得锁后才是真的可以往下执行。
- sleep:
sleep方法是Thread类的方法。
在一个线程中调用Thread.sleep()时,是告诉CPU不需要给当前线程分配时间片,让当前线程休眠,但是不释放锁。
当sleep的时间到了之后,当前线程继续往下执行。