synchronized的两种用法
- 对象锁
包括方法锁(默认锁对象为this当前实例对象)和同步代码块锁(自己指定锁对象)
- 类锁
指synchronized修饰 static方法 或指定锁对象为 Class对象
对象锁
同步代码块
使用 this 锁定代码块
public class SynchronizedObjectCodeBlock2 implements Runnable {
static SynchronizedObjectCodeBlock2 codeBlock2 = new SynchronizedObjectCodeBlock2();
@Override
public void run() {
synchronized (this) {
System.out.println("我是lock2, 我叫" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ", lock2 部分执行结束");
}
}
public static void main(String[] args) {
Thread thread1 = new Thread(codeBlock2);
Thread thread2 = new Thread(codeBlock2);
thread1.start();
thread2.start();
while (thread1.isAlive() || thread2.isAlive()) {
}
System.out.println("finished");
}
}
最终运行结果
我是lock2, 我叫Thread-0
Thread-0, lock2 部分执行结束
我是lock2, 我叫Thread-1
Thread-1, lock2 部分执行结束
finished
使用 自定义锁对象
public class SynchronizedObjectCodeBlock2 implements Runnable {
static SynchronizedObjectCodeBlock2 codeBlock2 = new SynchronizedObjectCodeBlock2();
private final Object lock1 = new Object();
private final Object lock2 = new Object();
@Override
public void run() {
synchronized (lock1) {
System.out.println("我是lock1, 我叫" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ", lock1 部分执行结束");
}
synchronized (lock2) {
System.out.println("我是lock2, 我叫" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ", lock2 部分执行结束");
}
}
public static void main(String[] args) {
Thread thread1 = new Thread(codeBlock2);
Thread thread2 = new Thread(codeBlock2);
thread1.start();
thread2.start();
while (thread1.isAlive() || thread2.isAlive()) {
}
System.out.println("finished");
}
}
运行结果,可以看出来加粗部分, thread-0和thread-1同时执行和同时结束,因为两个线程使用的不是同一把锁。
我是lock1, 我叫Thread-0
Thread-0, lock1 部分执行结束
我是lock2, 我叫Thread-0
我是lock1, 我叫Thread-1
Thread-1, lock1 部分执行结束
Thread-0, lock2 部分执行结束
我是lock2, 我叫Thread-1
Thread-1, lock2 部分执行结束
finished
方法锁
代码展示
public class SynchronizedObjectMethod3 implements Runnable {
public static void main(String[] args) {
SynchronizedObjectMethod3 objectMethod3 = new SynchronizedObjectMethod3();
Thread thread1 = new Thread(objectMethod3);
Thread thread2 = new Thread(objectMethod3);
thread1.start();
thread2.start();
}
@Override
public void run() {
method();
}
public synchronized void method() {
System.out.println("对象锁的方法修饰符形式, threadName=" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "运行结束");
}
}
运行结果:
使用synchronized修饰一个成员方法, 该方法会根据实例依次执行.
对象锁的方法修饰符形式, threadName=Thread-0
Thread-0运行结束
对象锁的方法修饰符形式, threadName=Thread-1
Thread-1运行结束
类锁
概念:
- 只有一个Class对象: Java类可能会有很多个实例对象, 但是只有一个Class对象
- 本质: 所谓的类锁, 实质上是Class对象的锁而已
- 用法和效果: 类锁只能在同一时刻被同一对象拥有
同步一个全局方法
代码展示
public class SynchronizedClassStatic4 implements Runnable {
static SynchronizedClassStatic4 instance1 = new SynchronizedClassStatic4();
static SynchronizedClassStatic4 instance2 = new SynchronizedClassStatic4();
@Override
public void run() {
method();
}
public static synchronized void method() {
System.out.println("我是类锁的第一种形式: static形式, 我叫 " + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "运行结束");
}
public static void main(String[] args) {
Thread thread1 = new Thread(instance1);
Thread thread2 = new Thread(instance2);
thread1.start();
thread2.start();
while (thread1.isAlive() || thread2.isAlive()) {
}
System.out.println("finished");
}
}
运行结果:
使用synchronized修饰一个全局方法(static修饰), synchronized默认使用类作为锁对象
我是类锁的第一种形式: static形式, 我叫 Thread-0
Thread-0运行结束
我是类锁的第一种形式: static形式, 我叫 Thread-1
Thread-1运行结束
finished
类锁同步一个代码块
代码展示
public class SynchronizedClassClass5 implements Runnable {
static SynchronizedClassClass5 instance1 = new SynchronizedClassClass5();
static SynchronizedClassClass5 instance2 = new SynchronizedClassClass5();
@Override
public void run() {
method();
}
private void method() {
synchronized(SynchronizedClassClass5.class) {
System.out.println("类锁的第二种表现形式, synchronized(*.class)的形式, 这是" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "运行结束");
}
}
public static void main(String[] args) {
Thread thread1 = new Thread(instance1);
Thread thread2 = new Thread(instance2);
thread1.start();
thread2.start();
while (thread1.isAlive() || thread2.isAlive()) {
}
System.out.println("finished");
}
}
运行结果:
尽管Thread使用的不同的instance对象, 但是使用了*.class类锁之后, 代码也会按照期望值运行.
类锁的第二种表现形式, synchronized(.class)的形式, 这是Thread-0
Thread-0运行结束
类锁的第二种表现形式, synchronized(.class)的形式, 这是Thread-1
Thread-1运行结束
finished