synchronized和Lock有什么区别,用新的lock有什么好处,举例说说

    回答这个问题,我们要从五个方面说起

  • 原始组成

synchronized是关键字属于jvm层面

monitorenter(底层是通过monitor对象来完成,其实wait/notify等方法也依赖于monitor对象只有在同步块或方法中才能调用wait/notify等方法)

Lock是具体类(java.util.concurrent.locks.Lock)是api层面的锁

  • 使用方法

synchronized不需要用户去手动释放锁,当synchronized代码执行完后系统会自动让线程释放对锁的占用

ReentrantLock则需要用户去手动释放锁若没有主动释放锁,则有可能导致出现死锁现象

需要lock()和unlock()方法配合try/finally语句块来完成

  • 等待是否可中断

synchronized不可中断,除非抛出异常或者正常运行完成

ReentrantLock可中断,1.设置超时方法tryLock(Long timeout, TimeUnit unit)

                      2.LockInterruptibly()放代码块中,调用interrupt()方法可中断

  • 加锁是否公平

synchronized非公平锁

ReentrantLock两者都可以,默认公平锁,构造方法中可以传入boolean值,true为公平锁,false为非公平锁

  • 锁绑定多个条件Condition

synchronized没有

ReentrantLock用来实现分组唤醒需要唤醒的线程们,可以精确唤醒,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。

    概念说到这里,接下来看一个demo,ReentrantLock是怎样精准唤醒线程的,还是多线程操作资源类,创建一个资源类,资源类中分别有打印5次,10次,15次的三个方法,然后创建三个线程,分别调用这三个方法,期待的效果是线程1打印完5次后,线程2打印10次,线程2打印完10次后,线程3打印15次,线程3打印完15次后,线程1在打印5次,就这样循环交替打印,来10轮。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionNotifyThreadDemo {

    public static void main(String[] args) {

        MyResource myResource = new MyResource();

        new Thread(() -> {

            for (int i = 0; i < 10; i++) {
                myResource.print5();
            }
        }, "t1\t").start();

        new Thread(() -> {

            for (int i = 0; i < 10; i++) {
                myResource.print10();
            }
        }, "t2\t").start();

        new Thread(() -> {

            for (int i = 0; i < 10; i++) {
                myResource.print15();
            }
        }, "t3\t").start();

    }

}

class MyResource {

    private int number = 1;
    private Lock lock = new ReentrantLock();
    private Condition c1 = lock.newCondition();
    private Condition c2 = lock.newCondition();
    private Condition c3 = lock.newCondition();

    public void print5() {

        try {
            lock.lock();
            while (number != 1) {
                c1.await();
            }

            for (int i = 1; i < 6; i++) {
                System.err.println(Thread.currentThread().getName() + "\t" + i);
            }
            number = 2;

            c2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void print10() {

        try {
            lock.lock();
            while (number != 2) {
                c2.await();
            }

            for (int i = 1; i < 11; i++) {
                System.err.println(Thread.currentThread().getName() + "\t" + i);
            }
            number = 3;

            c3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void print15() {

        try {
            lock.lock();
            while (number != 3) {
                c3.await();
            }

            for (int i = 1; i < 16; i++) {
                System.err.println(Thread.currentThread().getName() + "\t" + i);
            }
            number = 1;

            c1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
}

    在资源类(MyResource)中,通过lock的newCondition方法实例化三个条件类(Condition )的实例c1,c2,c3,依次使用在print5,print10,print15方法中,三个打印方法分别通过监视number变量来执行打印任务,print5方法,当number变量为1的时候打印,否则就执行c1的await方法等待,当打印成功后,将变量number设置为2,调用c2的signal方法,这样可以精准的唤醒线程2的调用print10方法,同样,print10方法,当number变量为2的时候打印,否则就执行c2的await方法等待,当打印成功后,将变量number设置为3,调用c3的signal方法,这样可以精准的唤醒线程3的调用print15方法,依次类推,就组成了一个print5→print10→print15→print5...的循环执行链,我们来看看结果

t1        1
t1        2
t1        3
t1        4
t1        5
t2        1
t2        2
t2        3
t2        4
t2        5
t2        6
t2        7
t2        8
t2        9
t2        10
t3        1
t3        2
t3        3
t3        4
t3        5
t3        6
t3        7
t3        8
t3        9
t3        10
t3        11
t3        12
t3        13
t3        14
t3        15
t1        1
t1        2
t1        3
t1        4
t1        5
t2        1
t2        2
t2        3
t2        4
t2        5
t2        6
t2        7
t2        8
t2        9
t2        10
t3        1
t3        2
t3        3
t3        4
t3        5
t3        6
t3        7
t3        8
t3        9
t3        10
t3        11
t3        12
t3        13
t3        14
t3        15

......

    就这样t1线程打印5次后,t2线程打印10次,t2线程打印完后,t3线程打印15次,循环调用,就这样实现了,多线程间精准唤醒某一个线程,大家可以动手试试,好了,今天文章到这里,下篇见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值