java锁机制的两种实现synchronized 与ReentrantLock

java的多线程环境下并发是常见问题,这两天看了锁相关的问题,记录下两个简单的用锁实现等待/唤醒机制的demo。

1.synchronized方式实现等待/唤醒。

public class WaitAndNotify {
    private static boolean flag = true;
    private static Object lock = new Object();
    public static void main(String[] args) {
        Thread waitThread = new Thread(new Wait(), "WaitThread");
        waitThread.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread notifyThread = new Thread(new Notify(), "NotifyThread");
        notifyThread.start();
    }
    private static class Wait implements Runnable {
        @Override
        public void run() {
            synchronized (lock) {
                while (flag) {
                    System.out.println(Thread.currentThread() + " flag是true,wait。。" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread() + " flag是false,开始继续工作" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            }
        }
    }
    private static class Notify implements Runnable {
        @Override
        public void run() {
            synchronized (lock){
                System.out.println(Thread.currentThread() + " 持有锁,发出通知" + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                lock.notifyAll();
                flag = false;
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

打印结果:

Thread[WaitThread,5,main] flag是true,wait。。18:55:28
Thread[NotifyThread,5,main] 持有锁,发出通知18:55:29
Thread[WaitThread,5,main] flag是false,开始继续工作18:55:34

分析:根据程序可以看到,大致的过程就是:WaitThread拿到lock对象的锁,然后根据flag标记,自己调用了wait()方法,从而释放锁并进入WAITTING状态。NotifyThread此时获取了lock对象的锁,然后进行notify操作,此时WaitThread被唤醒,但是,它不能立刻执行,因为唤醒线程NotifyThread还持有“该对象的同步锁”。必须等到NotifyThread线程释放了“对象的同步锁”之后,也就是同步代码块执行完以后,即睡眠5秒以后,等待线程WaitThread才能获取到“对象的同步锁”进而继续运行。

2.ReentrantLock方式实现等待/唤醒。

public class ReenterLockCondition {
    private static ReentrantLock lock = new ReentrantLock();

    private static Condition condition = lock.newCondition();

    private static Runnable runnable = () -> {
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName() + "进入等待。。");
            condition.await();
            System.out.println(Thread.currentThread().getName() + "继续执行");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    };

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(runnable, "thread--1");
        thread.start();

        Thread.sleep(2000);

        lock.lock();
        condition.signal();
        System.out.println("主线程发出信号");
        lock.unlock();
    }
}

打印结果:

thread--1进入等待。。
主线程发出信号
thread--1继续执行

分析:这里thread–1线程是等待线程,主线程就是唤醒想成。开始thread-1启动,拿到锁,然后进入等待并且释放锁,2秒后,主线程拿到锁,然后发出信号并释放锁,最后,thread–1继续执行。

 

相比Synchronized,ReentrantLock类提供了一些高级功能,主要有以下3项:

        1.等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized来说可以避免出现死锁的情况。

        2.公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁非公平锁,ReentrantLock默认的构造函数是创建的非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好。

        3.锁绑定多个条件,一个ReentrantLock对象可以同时绑定对个对象。

参考:https://blog.csdn.net/i_am_kop/article/details/80958856

https://blog.csdn.net/chenchaofuck1/article/details/51045134

你可能感兴趣的:(java)