java中synchronized获取锁和ReentrantLock

synchronized的局限性

synchronized是java内置的关键字,synchronized对同步锁的获取和释放锁由jvm实现,开发无法控制,可以认为是越底层的东西越高级越无法控制。
所以使用synchronized同步的情景
例如:
1、当线程尝试获取锁的时候,如果获取不到锁会一直阻塞,这个阻塞的过程,用户无法控制
2、如果获取锁的线程进入休眠或者阻塞,除非当前线程异常,否则其他线程尝试获取锁必须一直等待

ReentrantLock也可以同步方法,加锁

一般ReentrantLock的使用过程:

创建锁:ReentrantLock lock = new ReentrantLock();
获取锁:lock.lock()
释放锁:lock.unlock();
在同步方法的代码加锁,结束后释放锁

package com.example.demo.demo.reentrantLockDemo;

import java.util.concurrent.locks.ReentrantLock;

/**
 *
 * java中synchronize获取锁和ReentrantLock
 */
public class ReentrantLockTest {
    static int num =0;
    static ReentrantLock lock = new ReentrantLock();
    public static void addNum(){
        try {
            lock.lock();
            num++;
        }
        finally {
            lock.unlock();
        }
    }
     public static class Mythread extends  Thread{
         private String name;
         public Mythread(String name){
             this.name= name;
         }

         @Override
         public void run() {
             for (int i = 0; i <1000 ; i++) {
                 ReentrantLockTest.addNum();
             }
             
         }
         
     }

    public static void main(String[] args) throws InterruptedException {
        Mythread t1 = new Mythread("t1");
        t1.start();
        Mythread t2 = new Mythread("t2");
        t2.start();
        Mythread t3 = new Mythread("t3");
        t3.start();
        t1.join();
        t2.join();
        t3.join();
        System.out.println(num);
    }
}

通过lock(),和unlock()可以灵活控制锁的获取与释放,注意lock.unlock()一定要放在finally中,否则,若程序出现了异常,锁没有释放(会一直同步占用),那么其他线程就再也没有机会获取这个锁了

ReentrantLock是可重入锁

顾名思义可以加多把锁

try {
            lock.lock();
             lock.lock();
            num++;
        }
        finally {
            lock.unlock();
            lock.unlock();
        }

需要注意获取锁和释放锁是成对出现的

公平锁和非公平锁的概念

当获取锁是系统只是会从这个锁的等待队列中随机挑选一个,不管队列中的顺序,是非公平锁。反之先来先获取为公平锁,synchronized默认有jvm内部实现控制的,是非公平锁

ReentrantLock公平锁与非公平锁

jdk中ReentrantLock的源码,2个构造方法:

public ReentrantLock () {
        sync = new NonfairSync();
    }

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

存在无参和有参数
默认构造方法创建的是非公平锁。

第2个构造方法,有个fair参数,当fair为true的时候创建的是公平锁,公平锁看起来很不错,不过要实现公平锁,系统内部肯定需要维护一个有序队列,因此公平锁的实现成本比较高,性能相对于非公平锁来说相对低一些。因此,在默认情况下,锁是非公平的,如果没有特别要求,则不建议使用公平锁。

private static ReentrantLock fairLock = new ReentrantLock(true);
 fairLock.lock();//公平锁
 fairLock.unlock();

ReentrantLock其他加锁的方法

lockInterruptibly()
就是在等的获取锁的过程中(发起获取锁请求到还未获取到锁这段时间内)是可以被中断的,也就是说在等待锁的过程中,程序可以根据需要取消获取锁的请求

private static ReentrantLock Lock = new ReentrantLock(true);
Lock.lockInterruptibly();//加锁获取锁时,在线程调用interrupt()方法之后,才会引发 InterruptedException异常

tryLock无参方法

public boolean tryLock()

返回boolean类型的值,此方法会立即返回,结果表示获取锁是否成功

public class Demo8 {
    private static ReentrantLock    =new ReentrantLock(false);
    public static class T extends Thread {
        public T(String name) {
            super(name);
        }
        @Override
        public void run() {
            try { 
                System.out.println(System.currentTimeMillis() + ":" + this.getName() + "开始获取锁!");//获取锁超时时间设置为3秒,3秒内是否能否获取锁都会返回
                if (lock1.tryLock())
                { 
                    System.out.println(System.currentTimeMillis() + ":" + this.getName() + "获取到了锁!");
                    //获取到锁之后,休眠5秒
                    TimeUnit.SECONDS.sleep(5);
                }
                else
                {
                    System.out.println(System.currentTimeMillis() + ":" + this.getName() + "未能获取到锁!");
                }
            }
            catch (InterruptedException e)
            { 
                e.printStackTrace();
            }
            finally
            {
                if (lock1.isHeldByCurrentThread())
                {
                    lock1.unlock();
                }
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        T t1 = new T("t1");
        T t2 = new T("t2");
        t1.start();
        t2.start();
    }
}
1563356291081:t2开始获取锁!
1563356291081:t2获取到了锁!
1563356291081:t1开始获取锁!
1563356291081:t1未能获取到锁!

可以看到t2获取成功,t1获取失败了,tryLock()是立即响应的,中间不会有阻塞。

tryLock有参方法

可以明确设置获取锁的超时时间,该方法签名:

public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException

将上面代码中的lock1.tryLock()替换


lock1.tryLock(3,TimeUnit.SECONDS)

程序中调用了ReentrantLock的实例方法 tryLock(3,TimeUnit.SECONDS),表示获取锁的超时时间是3秒,3秒后不管是否能否获取锁,该方法都会有返回值,获取到锁之后,内部休眠了5秒
会导致会导致另外一个线程获取锁失败。

1563355512901:t2 开始获取锁!
   1563355512901:t1 开始获取锁!
   1563355512902:t2 获取到了锁!
   1563355515904:t1 未能获取到锁!

总结

1. ReentrantLock可以实现公平锁和非公平锁
2. ReentrantLock默认实现的是非公平锁
3. ReentrantLock的获取锁和释放锁必须成对出现,锁了几次,也要释放几次
4. 释放锁的操作必须放在finally中执行
5. lockInterruptibly()实例方法可以相应线程的中断方法,调用线程的interrupt()方法时,
6. lockInterruptibly()方法会触发 InterruptedException异常
7. 关于 InterruptedException异常说一下,看到方法声明上带有 throwsInterruptedException,表示该方法可以相应线程中断,调用线程的interrupt()方法时,这些方法会触发 InterruptedException异常,触发InterruptedException时,线程的中断中断状态会被清除。所以如果程序由于调用 interrupt()方法而触发 InterruptedException异常,线程的标志由默认的false变为ture,然后又变为false
8. 实例方法tryLock()获会尝试获取锁,会立即返回,返回值表示是否获取成功
9. 实例方法tryLock(long timeout, TimeUnit unit)会在指定的时间内尝试获取锁,指定的时间内是否能够获取锁,都会返回,返回值表示是否获取锁成功,该方法会响应线程的中断

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值