Java线程同步之ReentrantLock快速入门

2019-06-10 10:12:21  阅读 136 次 评论 0 条

关于ReentrantLock的介绍网上好文章很多,写的很详细,但对于不太想深入了解,但又马上想用的人可能就有点麻烦了。本文的目的是直接演示使用方法,帮助大家快速入门。

使用ReentrantLock就是为了实现线程间的同步


示例1

private Lock lock = new ReentrantLock();

private void test(){
    new Thread(new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "thread 1");
            
            lock.lock();
            Log.d(TAG, "lock 1");

            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            lock.unlock();
            Log.d(TAG, "unlock 1");

        }
    }).start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "thread 2");

            lock.lock();
            Log.d(TAG, "lock 2");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            lock.unlock();
            Log.d(TAG, "unlock 2");

        }
    }).start();
}

执行结果

06-10 10:06:16.618 1947-1985/com.example.test.myapplication D/MainActivity: thread 1
06-10 10:06:16.618 1947-1985/com.example.test.myapplication D/MainActivity: lock 1
06-10 10:06:16.618 1947-1986/com.example.test.myapplication D/MainActivity: thread 2
06-10 10:06:21.620 1947-1985/com.example.test.myapplication D/MainActivity: unlock 1
06-10 10:06:21.621 1947-1986/com.example.test.myapplication D/MainActivity: lock 2
06-10 10:06:26.621 1947-1986/com.example.test.myapplication D/MainActivity: unlock 2

可见,thread1调用lock.lock()获取锁之后,thread2运行到 lock.lock() 时只能等待,等thread1调用lock.unlock()之后 thread2才能获取到锁,继续执行。

也就是lock()和unlock() 之前的代码实现了线程同步,一套执行完才能进入下一个lock/unlock 对。


示例2

private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();


private void test(){
    new Thread(new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "thread 1");

            lock.lock();
            Log.d(TAG, "lock 1");

            try {
                Thread.sleep(5000);
                Log.d(TAG, "wait 1");
                c1.await();

            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            lock.unlock();
            Log.d(TAG, "unlock 1");

        }
    }).start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "thread 2");

            lock.lock();
            Log.d(TAG, "lock 2");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            c1.signal();
            Log.d(TAG,"signal 2");

            lock.unlock();
            Log.d(TAG, "unlock 2");

        }
    }).start();
}

执行结果

06-10 10:40:00.570 2051-2077/com.example.test.myapplication D/MainActivity: thread 1
06-10 10:40:00.576 2051-2077/com.example.test.myapplication D/MainActivity: lock 1
06-10 10:40:00.578 2051-2078/com.example.test.myapplication D/MainActivity: thread 2
06-10 10:40:05.586 2051-2077/com.example.test.myapplication D/MainActivity: wait 1
06-10 10:40:05.586 2051-2078/com.example.test.myapplication D/MainActivity: lock 2
06-10 10:40:10.632 2051-2078/com.example.test.myapplication D/MainActivity: signal 2
06-10 10:40:10.633 2051-2078/com.example.test.myapplication D/MainActivity: unlock 2
06-10 10:40:10.633 2051-2077/com.example.test.myapplication D/MainActivity: unlock 1

thread1获取到锁后,在线程中调用c1.await(); 开始等待,此时释放锁,thread2在lock()处获取到锁,且thread2锁内的代码执行完后,调用unlock(),thread1才会继续执行,当然,需要在thread2中使用c1.signal()通知 thread1结束等待。

那么,将thread1中的c1.await()改成 超时等待,到了时间会不会自动往下走呢?答案是不会,看例子


示例3

private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();

private void test(){
    new Thread(new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "thread 1");

            lock.lock();
            Log.d(TAG, "lock 1");

            try {
                Thread.sleep(5000);
                Log.d(TAG, "wait 1");
                c1.await(1000, TimeUnit.MILLISECONDS);
                Log.d(TAG, "wait timeout 1");

            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            lock.unlock();
            Log.d(TAG, "unlock 1");

        }
    }).start();

    new Thread(new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "thread 2");

            lock.lock();
            Log.d(TAG, "lock 2");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            c1.signal();
            Log.d(TAG,"signal 2");

            lock.unlock();
            Log.d(TAG, "unlock 2");

        }
    }).start();
}

执行结果

06-10 10:51:17.179 2142-2169/com.example.test.myapplication D/MainActivity: thread 1
06-10 10:51:17.181 2142-2169/com.example.test.myapplication D/MainActivity: lock 1
06-10 10:51:17.181 2142-2170/com.example.test.myapplication D/MainActivity: thread 2
06-10 10:51:22.189 2142-2169/com.example.test.myapplication D/MainActivity: wait 1
06-10 10:51:22.191 2142-2170/com.example.test.myapplication D/MainActivity: lock 2
06-10 10:51:27.193 2142-2170/com.example.test.myapplication D/MainActivity: signal 2
06-10 10:51:27.193 2142-2170/com.example.test.myapplication D/MainActivity: unlock 2
06-10 10:51:27.194 2142-2169/com.example.test.myapplication D/MainActivity: wait timeout 1
06-10 10:51:27.194 2142-2169/com.example.test.myapplication D/MainActivity: unlock 1

c1.await(1000, TimeUnit.MILLISECONDS); 只等待了1秒,而thread2需要运行5秒,虽然超时了,但thread2没有释放锁,thread1也只能继续等待。


总结:多个线程中lock()和unlock()间的代码必须一套跑完才能继续走下一个,当使用await释放锁后,需要等其它线程跑完整个lock()-unlock()流程才能继续。


本文地址:http://www.bloguan.com/?id=520
版权声明:本文为原创文章,版权归 博观网 所有,欢迎分享本文,转载请保留出处!

发表评论


表情

还没有留言,还不快点抢沙发?