syschronized的使用、原理以及与重入锁ReenTrantLock的比较

http://www.cnblogs.com/paddix/p/5367116.html

syschronized的使用

(1)确保线程互斥的访问同步代码
(2)保证共享变量的修改能够及时可见
(3)有效解决重排序问题

从语法上讲,Synchronized总共有三种用法:
  (1)修饰普通方法
4 public synchronized void method1(){
5 System.out.println(“Method 1 start”);
6 try {
7 System.out.println(“Method 1 execute”);
8 Thread.sleep(3000);
9 } catch (InterruptedException e) {
10 e.printStackTrace();
11 }
12 System.out.println(“Method 1 end”);
13 }
14
  (2)修饰静态方法
public static synchronized void method1(){
5 System.out.println(“Method 1 start”);
6 try {
7 System.out.println(“Method 1 execute”);
8 Thread.sleep(3000);
9 } catch (InterruptedException e) {
10 e.printStackTrace();
11 }
12 System.out.println(“Method 1 end”);
13 }

  (3)修饰代码块
4 public void method1(){
5 System.out.println(“Method 1 start”);
6 try {
7 synchronized (this) {
8 System.out.println(“Method 1 execute”);
9 Thread.sleep(3000);
10 }
11 } catch (InterruptedException e) {
12 e.printStackTrace();
13 }
14 System.out.println(“Method 1 end”);
15 }

syschronized的原理

4 public void method() {
5 synchronized (this) {
6 System.out.println(“Method 1 start”);
7 }
8 }

反编译以上代码得
这里写图片描述
monitorenter :
每个对象有一个监视器锁(monitor)。当monitor被占用时就会处于锁定状态,线程执行monitorenter指令时尝试获取monitor的所有权,过程如下:
1、如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者。
2、如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1.
3.如果其他线程已经占用了monitor,则该线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor的所有权。

monitorexit:
执行monitorexit的线程必须是objectref所对应的monitor的所有者。

通过这两段描述,我们应该能很清楚的看出Synchronized的实现原理,

Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。

syschronized 与 lock(重入锁ReenTrantLock)

https://www.cnblogs.com/iyyy/p/7993788.html
1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类;

2.synchronized无法获得锁的状态,因此会自动释放锁。(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需要在finally中调用Unlock()手工释放。

3.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;

4.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可中断、可公平、绑定多个Condition.(两者皆可重入)
重入:可以再进入的锁。同一个线程每次进入一次,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。
等待可中断:在持有锁的线程长时间不释放锁的时候,等待的线程可以选择放弃等待. tryLock(long timeout, TimeUnit unit)
公平锁按照申请锁的顺序来一次获得锁称为公平锁.
绑定多个Condition 通过多次newCondition可以获得多个Condition对象,可以简单的实现比较复杂的线程同步的功能.通过await(),signal();

5.Lock锁适合大量同步的代码问题,synchronized锁适合代码少量的同步问题。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
重入(ReentrantLock)是一种独占,也就是说同一时间只能有一个线程持有该。与 synchronized 关键字不同的是,重入可以支持公平和非公平两种模式,而 synchronized 关键字只支持非公平重入的实现原理是基于 AQS(AbstractQueuedSynchronizer)框架,利用了 CAS(Compare And Swap)操作和 volatile 关键字。 重入的核心思想是“可重入性”,也就是说如果当前线程已经持有了该,那么它可以重复地获取该而不会被阻塞。在重入内部,使用了一个计数器来记录当前线程持有该的次数。每当该线程获取一次时,计数器就加 1,释放一次时,计数器就减 1,只有当计数器为 0 时,其他线程才有机会获取该重入的基本使用方法如下: ```java import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockTest { private static final ReentrantLock lock = new ReentrantLock(); public static void main(String[] args) { new Thread(() -> { lock.lock(); try { System.out.println(Thread.currentThread().getName() + " get lock"); Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); System.out.println(Thread.currentThread().getName() + " release lock"); } }, "Thread-1").start(); new Thread(() -> { lock.lock(); try { System.out.println(Thread.currentThread().getName() + " get lock"); } finally { lock.unlock(); System.out.println(Thread.currentThread().getName() + " release lock"); } }, "Thread-2").start(); } } ``` 在上面的示例代码中,我们创建了两个线程,分别尝试获取重入。由于重入支持可重入性,因此第二个线程可以成功地获取到该,而不会被阻塞。当第一个线程释放后,第二个线程才会获取到并执行相应的操作。 需要注意的是,使用重入时一定要记得在 finally 块中释放,否则可能会导致死的问题。同时,在获取时也可以设置超时时间,避免由于获取失败而导致的线程阻塞问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值