同步互斥
Java 对于共享资源的互斥访问提供了在 Jvm 层面基于 synchronized 实现, JDK 层面基于 ReentrantLock 来实现
synchronized
同步代码块
只作用同一个对象,如果调用不同对象的同步代码块,就不会进行同步
java
public class SynchronizedObjectDemo {
/*
同步一个代码块:作用同一个对象
*/
public void executor() {
synchronized (this) {
for (int i =0; i < 10; i++) {
System.out.print(i + " ");
}
}
}
public static void test1() throws InterruptedException {
SynchronizedObjectDemo demo = new SynchronizedObjectDemo();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(demo::executor);
executorService.execute(demo::executor);
Thread.sleep(2);
executorService.shutdown();
}
public static void test2() throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
SynchronizedObjectDemo demo1 = new SynchronizedObjectDemo();
SynchronizedObjectDemo demo2 = new SynchronizedObjectDemo();
executorService.execute(demo1::executor);
executorService.execute(demo2::executor);
Thread.sleep(2);
executorService.shutdown();
}
public static void main(String[] args) throws InterruptedException{
test1();
test2();
}
}
test1 方法执行结果如下:
由于调用同一个对象的同步代码块,因此这两个线程回进行同步,当一个线程进入同步语句,另外一个对象就必须等待
text
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
text2 方法执行结果如下:
两个线程调用了不同对象的同步代码块,因此两个线程不需要同步,从运行结果可以看到交叉执行
text
0 1 0 2 3 1 4 5 2 3 6 4 7 8 5 9 6 7 8 9
同步一个方法
java
public class SynchronizedMethodDemo {
public synchronized void executor() {
for (int i =0; i< 10; i++) {
System.out.print(i +" ");
}
}
public static void test1() throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
SynchronizedMethodDemo demo = new SynchronizedMethodDemo();
executorService.execute(demo::executor);
executorService.execute(demo::executor);
Thread.sleep(2000);
executorService.shutdown();
}
public static void test2() throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
SynchronizedMethodDemo demo = new SynchronizedMethodDemo();
SynchronizedMethodDemo demo1 = new SynchronizedMethodDemo();
executorService.execute(demo::executor);
executorService.execute(demo1::executor);
Thread.sleep(2000);
executorService.shutdown();
}
public static void main(String[] args) throws InterruptedException {
test1();
test2();
}
}
test1 方法执行结果如下:
text
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
text2 方法执行结果如下:
text
0 1 0 2 3 1 4 5 2 3 6 4 7 8 5 9 6 7 8 9
同步一个类
java
public class SynchronizedClassDemo {
public void executor() {
synchronized (SynchronizedClassDemo.class) {
for (int i =0 ;i < 10; i++) {
System.out.print(i + " ");
}
}
}
public static void test() throws InterruptedException {
SynchronizedClassDemo demo = new SynchronizedClassDemo();
ExecutorService pool = Executors.newCachedThreadPool();
pool.execute(demo::executor);
pool.execute(demo::executor);
Thread.sleep(2000);
pool.shutdown();
}
public static void test1() throws InterruptedException {
SynchronizedClassDemo demo = new SynchronizedClassDemo();
SynchronizedClassDemo demo1 = new SynchronizedClassDemo();
ExecutorService pool = Executors.newCachedThreadPool();
pool.execute(demo::executor);
pool.execute(demo1::executor);
Thread.sleep(2000);
pool.shutdown();
}
public static void main(String[] args) throws InterruptedException {
test1();
}
}
作⽤于整个类,也就是说两个线程调⽤同⼀个类的不同对象上的这种同步语句,也会进⾏同 步。
test 跟 test1() 输出一样的,如下:
text
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
同步一个静态方法
java
public class SynchronizedStaticMethod {
public synchronized static void executor() {
for (int i=0;i<10;i++) {
System.out.print( i + " ");
}
}
public static void test() {
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(SynchronizedStaticMethod::executor);
executorService.execute(SynchronizedStaticMethod::executor);
}
public static void main(String[] args) {
test();
}
}
作用这个类, 会进行同步等待
输出如下:
text
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
ReentrantLock
java
public class ReentrantLockDemo {
private Lock lock = new ReentrantLock();
public void executor() {
lock.lock();
try {
for (int i = 0; i < 10; i++) {
System.out.print( i + " ");
}
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockDemo demo = new ReentrantLockDemo();
ExecutorService service = Executors.newCachedThreadPool();
service.execute(demo::executor);
service.execute(demo::executor);
}
}
输出如下
text
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
比较
锁的实现 | 性能 | 等待可中断 | 公平锁 | 锁绑定多个条件 |
---|---|---|---|---|
synchronized 是 JVM 实现,ReentrantLock 是 JDK 实现的 | 新版对 synchronized 进行了优化, 添加了自旋锁, 性能差距不大 | ReentrantLock 可中断,synchronized 不行 | synchronized 非公平,ReentrantLock 默认非公平,可传参数变为公平 | ReentrantLock 可以绑定多条件 |
推荐
除非需要使用 ReentrantLock 高级功能,否则优先使用 synchronized,synchronized 是 JVM 实现的⼀种锁机制,不需要⼿动释放锁,⽽ ReentrantLock 是 JDK 实现的,需要⼿动释放锁,如果没有及时释放锁,那么就可能造成死锁。