多线程(一):Synchronized与ReentrantLock

Java 提供了两种锁机制来控制多个线程对共享资源的互斥访问,第一个是 JVM 实现的 synchronized,而另一个是
JDK 实现的 ReentrantLock

Synchronized

synchronized同步(加锁)的四种方式
对于Synchronized来说,可以同步代码块方法类对象静态方法

  1. 代码块
public void func() {
    synchronized (this) {
		// ... 
	}
}

synchronized同步一个代码块,但是在同步之前,synchronized要先拿到一把锁,也就是this对象。
这就表示着如果两个线程都想运行一个对象的方法func()时,那么他们是互斥的。
对这种情况的线程来说,有则执行,无则等待。

public class SynchronizedPra {
    public static void main(String[] args) {
    	//针对SynchronizedPra类,只有一个对象实例s1
    	//那么当线程池service产生的多个线程都想运行s1对象的方法func1()时,只有拿到锁的线程可以运行。
        SynchronizedPra s1  = new SynchronizedPra();
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(() -> s1.func1());
        service.execute(() -> s1.func1());
    }
	//该方法中有一个同步代码块,意味着多线程模式下,谁拿到当前对象的锁,谁执行。
public void func1() {
        synchronized (this) {
            for (int i = 0; i < 10; i++) {
                System.out.print(i + "  ");
            }
        }
    }
//运行结果是规则的
0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5  6  7  8  9  

如果两个线程运行两个对象的方法func()时,那么他们是互斥的。
对这种情况的线程来说,无需等待。

public class SynchronizedPra {
    public static void main(String[] args) {
    	//两个对象实例s1,s2
        SynchronizedPra s1 = new SynchronizedPra();
        SynchronizedPra s2 = new SynchronizedPra();
        //service生成两个线程运行的是不同对象的func1()方法,拿到的是不同的锁,不会互相影响。
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(() -> s1.func1());
        service.execute(() -> s2.func1());
    }
    public void func1() {
        synchronized (this) {
            for (int i = 0; i < 10; i++) {
                System.out.print(i + "  ");
            }
        }
    }
}
//运行结果呈不确定性,这要取决于两个线程什么时候启动
0  1  2  3  4  0  1  2  3  5  6  7  8  9  4  5  6  7  8  9
  1. 方法
public synchronized void func () {
    // ...
}

它和同步代码块一样,作用于同一个对象。

  1. 类对象
public void func() {
    synchronized (SynchronizedExample.class) {
// ... }
}

每个类的类对象在内存都是唯一的,所以synchronized锁住类对象,相当于锁住该类
对所有线程来说,无论是运行哪个对象实例func1()方法,都是有则执行,无则等待。

public class SynchronizedPra {
    public static void main(String[] args) {
        SynchronizedPra s1 = new SynchronizedPra();
        SynchronizedPra s2 = new SynchronizedPra();

        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(() -> s1.func1());
        service.execute(() -> s2.func1());
    }
    public void func1() {
        synchronized (SynchronizedPra.class) {
            for (int i = 0; i < 10; i++) {
                System.out.print(i + "  ");
            }
        }
    }
}
  1. 静态方法
public synchronized static void fun() {
    // ...
}

和上面一样,作用于整个类。

ReentrantLock

ReentrantLock 是 java.util.concurrent(J.U.C)包中的锁。

public class ReentrantLockPra {
	//类初始化时会生成ReentrantLock实例
    private Lock lock = new ReentrantLock();
   
    public static void main(String[] args) {
    	//多个线程运行func1()时,首先运行的线程会先加锁,待运行完毕后释放锁,其他线程才能继续运行。
        ReentrantLockPra s1 = new ReentrantLockPra();
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(() -> s1.func1());
        service.execute(() -> s1.func1());
    }
    
    public void func1() {
		//加锁
        lock.lock();
        try {
            for (int i = 0; i < 10; i++) {
                System.out.print(i + "  ");
            }
        }finally {
        	// 确保释放锁,从而避免发生死锁。
            lock.unlock();
        }
    }
}

二者之间的比较

  1. 锁的实现
    synchronized 是 JVM 实现的,而 ReentrantLock 是 JDK 实现的。
  2. 性能
    新版本 Java 对 synchronized 进行了很多优化,例如自旋锁等,synchronized 与 ReentrantLock 大致相同。
  3. 等待可中断
    当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情。 ReentrantLock 可中断,而 synchronized 不行。
  4. 公平锁
    公平锁是指多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁。
    synchronized 中的锁是非公平的,ReentrantLock 默认情况下也是非公平的,但是也可以是公平的。
  5. 锁绑定多个条件
    一个 ReentrantLock 可以同时绑定多个 Condition 对象。
  6. 使用选择
    除非需要使用 ReentrantLock 的高级功能,否则优先使用 synchronized。这是因为 synchronized 是 JVM 实现的一 种锁机制,JVM 原生地支持它,而 ReentrantLock 不是所有的 JDK 版本都支持。并且使用 synchronized 不用担心没有释放锁而导致死锁问题,因为 JVM 会确保锁的释放。

ReentrantLock学习在之后的JUC学习中再继续补充,这里只是列举出Java中两种锁机制

发布了352 篇原创文章 · 获赞 73 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43777983/article/details/104987447
今日推荐