在包java.util.concurrent.locks
下面可以看到两个接口Lock、ReadWriteLock
,分别对应着两种实现方式ReentrantLock、ReentrantReadWriteLock
。Lock
中定义了下面一组方法
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
其中Condition newCondition();
涉及到Condition
,后面单独记录
上面是Lock
接口中定义的所有方法,除了Condition
之外只有两类,加锁和解锁。其中加锁方法4个
-
lock()
,无返回值,获取锁成功代码向下执行,否则阻塞线程直到获取到锁 -
lockInterruptibly()
,同上,但是如果在别处调用了当前线程的interrupt()
函数终止线程,使用这个方法可以及时得到这个状态,lock()
则不会 -
tryLock()
,有返回值,立即返回获取锁状态,成功true,失败false -
tryLock(long time, TimeUnit unit)
,有返回值,若获取锁成功就直接返回;获取锁失败就阻塞设置的时间,如果设置的时间内获取锁成功就返回true,超时之后返回false
解锁方法1个:unlock()
,一次加锁对应着一次解锁,不能少也不能多
1、代码演示:lock()
package com.hpplay.threadcommunicationdemo;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by DON on 2017/3/7.
*/
public class ReentrantLockFragment extends Fragment {
private static final String TAG = "ReentrantLockFragment";
private Lock lock = new ReentrantLock();
private ThreadA threadA = new ThreadA();
private ThreadB threadB = new ThreadB();
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
RelativeLayout relativeLayout = new RelativeLayout(getActivity());
return relativeLayout;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//程序入口
threadA.start();
threadB.start();
}
private class ThreadA extends Thread {
@Override
public void run() {
super.run();
Log.e(TAG, this.getClass().getSimpleName() + " before");
lock.lock();
Log.e(TAG, this.getClass().getSimpleName() + " start");
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
Log.e(TAG, this.getClass().getSimpleName() + " end");
lock.unlock();
}
}
private class ThreadB extends Thread {
@Override
public void run() {
super.run();
Log.e(TAG, this.getClass().getSimpleName() + " before");
lock.lock();
Log.e(TAG, this.getClass().getSimpleName() + " start");
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
Log.e(TAG, this.getClass().getSimpleName() + " end");
lock.unlock();
}
}
}
代码很简单,就不赘述了,分析打印的log
03-08 15:18:27.297 6461-6606/? E/ReentrantLockFragment: ThreadA before
//A线程开始执行
03-08 15:18:27.297 6461-6606/? E/ReentrantLockFragment: ThreadA start
//A线程加锁成功, A线程的任务开始执行
03-08 15:18:27.297 6461-6607/? E/ReentrantLockFragment: ThreadB before
//B线程开始执行,由于A线程加锁成功,B线程阻塞等待
03-08 15:18:29.298 6461-6606/? E/ReentrantLockFragment: ThreadA end
//A线程任务执行完毕,解锁
03-08 15:18:29.299 6461-6607/? E/ReentrantLockFragment: ThreadB start
//B线程加锁成功,开始执行任务
03-08 15:18:31.301 6461-6607/? E/ReentrantLockFragment: ThreadB end
//B线程任务执行完毕,解锁
2、代码演示:lockInterruptibly()
对上述代码做一些修改,将线程B的加锁方式改为lockInterruptibly()
,同时在线程A中调用线程B的 interrupt()
方法,修改后的代码如下
private class ThreadA extends Thread {
@Override
public void run() {
super.run();
Log.e(TAG, this.getClass().getSimpleName() + " before");
lock.lock();
Log.e(TAG, this.getClass().getSimpleName() + " start");
try {
Thread.sleep(500);
threadB.interrupt();//终止B线程
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
Log.e(TAG, this.getClass().getSimpleName() + " end");
lock.unlock();
}
}
private class ThreadB extends Thread {
@Override
public void run() {
super.run();
Log.e(TAG, this.getClass().getSimpleName() + " before");
try {
lock.lockInterruptibly();
Log.e(TAG, this.getClass().getSimpleName() + " start");
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
Log.e(TAG, this.getClass().getSimpleName() + " end");
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
Log.e(TAG, this.getClass().getSimpleName() + " Interrupted ");
}
}
}
分析log信息
03-08 15:29:02.243 7069-7097/? E/ReentrantLockFragment: ThreadA before
//A线程开始执行
03-08 15:29:02.243 7069-7097/? E/ReentrantLockFragment: ThreadA start
//A线程加锁成功,任务开始执行
03-08 15:29:02.245 7069-7098/? E/ReentrantLockFragment: ThreadB before
//B线程开始执行,加锁失败,阻塞等待
03-08 15:29:02.245 7069-7098/? E/ReentrantLockFragment: ThreadB Interrupted
//500ms之后,A线程调用了threadB.interrupt();,B线程收到终止消息
03-08 15:29:04.745 7069-7097/? E/ReentrantLockFragment: ThreadA end
//A线程任务执行完毕,解锁
上面的例子中当B线程被终止时,B线程及时的收到了消息。如果这时候B线程不使用lock.lockInterruptibly();
方法,会是什么样子呢?
将线程B的代码改回来
private class ThreadB extends Thread {
@Override
public void run() {
super.run();
Log.e(TAG, this.getClass().getSimpleName() + " before");
lock.lock();
Log.e(TAG, this.getClass().getSimpleName() + " start");
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
Log.e(TAG, this.getClass().getSimpleName() + " end");
lock.unlock();
}
}
运行程序,分析log信息
03-08 15:35:27.565 7559-7624/? E/ReentrantLockFragment: ThreadA before
//A线程开始执行
03-08 15:35:27.565 7559-7624/? E/ReentrantLockFragment: ThreadA start
//A线程加锁成功,开始执行任务
03-08 15:35:27.567 7559-7625/? E/ReentrantLockFragment: ThreadB before
//B线程开始执行,加锁失败,阻塞
03-08 15:35:30.067 7559-7624/? E/ReentrantLockFragment: ThreadA end
//A线程任务执行完毕,解锁。中间调用 threadB.interrupt();,B线程并没有收到消息
03-08 15:35:30.070 7559-7625/? E/ReentrantLockFragment: ThreadB start
//B线程加锁成功,开始执行任务
03-08 15:35:30.071 7559-7625/? W/System.err: at com.hpplay.threadcommunicationdemo.ReentrantLockFragment$ThreadB.run(ReentrantLockFragment.java:75)
//由于前面已经调用B线程的interrupt()方法,这里调用Thead.sleep(2000),发生异常,线程没有沉睡2秒,发生异常
03-08 15:35:30.072 7559-7625/? E/ReentrantLockFragment: ThreadB end
//B线程任务执行完毕,解锁
3、代码演示:tryLock()
,能及时返回加锁状态
修改ThreadA和ThreadB代码
private class ThreadA extends Thread {
@Override
public void run() {
super.run();
Log.e(TAG, this.getClass().getSimpleName() + " before");
if(lock.tryLock()) {
Log.e(TAG, this.getClass().getSimpleName() + " start");
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
Log.e(TAG, this.getClass().getSimpleName() + " end");
lock.unlock();
}
}
}
private class ThreadB extends Thread {
@Override
public void run() {
super.run();
Log.e(TAG, this.getClass().getSimpleName() + " before");
if(lock.tryLock()) {
Log.e(TAG, this.getClass().getSimpleName() + " start");
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
Log.e(TAG, this.getClass().getSimpleName() + " end");
lock.unlock();
}
}
}
运行,分析log信息
03-08 16:52:23.865 9169-9826/? E/ReentrantLockFragment: ThreadA before
//A线程开始执行
03-08 16:52:23.865 9169-9826/? E/ReentrantLockFragment: ThreadA start
//A线程加锁成功,开始执行任务
03-08 16:52:23.871 9169-9827/? E/ReentrantLockFragment: ThreadB before
//B线程开始执行,加锁失败,返回false
03-08 16:52:25.866 9169-9826/? E/ReentrantLockFragment: ThreadA end
//A线程任务执行完毕,解锁
4、代码演示:tryLock(long time, TimeUnit unit)
主要是跟tryLock()
相比,上面可以看到tryLock()
失败就直接返回false,tryLock(long time, TimeUnit unit)
如果获取锁失败,就会阻塞,并且会在设置的时间去获取锁,成功就返回true。
修改ThreadB代码
private class ThreadB extends Thread {
@Override
public void run() {
super.run();
Log.e(TAG, this.getClass().getSimpleName() + " before");
boolean isLock = false;
try {
isLock = lock.tryLock(5, TimeUnit.SECONDS);//如果获取锁成功就向下执行
// ,如获取失败线程阻塞5秒,若5秒内仍未获取成功,返回false
}catch (InterruptedException e){//如果在等待期间被别的线程终止线程,就会进入这里
e.printStackTrace();
isLock = false;
}
if(isLock) {
Log.e(TAG, this.getClass().getSimpleName() + " start");
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
Log.e(TAG, this.getClass().getSimpleName() + " end");
lock.unlock();
}
}
}
运行,分析log信息
03-08 17:03:36.413 10722-10761/? E/ReentrantLockFragment: ThreadA before
//A线程启动
03-08 17:03:36.413 10722-10761/? E/ReentrantLockFragment: ThreadA start
//A线程加锁成功,并开始执行任务
03-08 17:03:36.413 10722-10762/? E/ReentrantLockFragment: ThreadB before
//B线程启动,加锁失败,阻塞
03-08 17:03:38.415 10722-10761/? E/ReentrantLockFragment: ThreadA end
//2秒之后A线程执行完毕,解锁
03-08 17:03:38.416 10722-10762/? E/ReentrantLockFragment: ThreadB start
//B线程加锁成功,开始执行任务
03-08 17:03:40.417 10722-10762/? E/ReentrantLockFragment: ThreadB end
//B线程执行任务完毕,解锁
网友评论