Android多线程专题:线程间协作Lock、ReadWriteLock
程序员文章站
2022-03-08 13:16:51
synchronized提供了同步访问,而Lock也提供了同步访问。 如果代码块被synchronized修饰后,当一个线程获取了对应的锁,并执行该代码时,其它线程只能一直等待,等待获取锁的线程释放锁,而释放锁的情况只有当获取锁的线程执行完毕或者对应的线程发生异常;因此需要一种机制,可以不让等待的线程一直无限期的等待,而Lock就可以完成Lock的主要特点可以知道线程有没有成功获取到锁多个线程都只是进行读操作时,线程之间不会发生冲突尝试去拿锁,如果拿不到锁,则等待一段时间......
synchronized提供了同步访问,而Lock也提供了同步访问。
如果代码块被synchronized修饰后,当一个线程获取了对应的锁,并执行该代码时,其它线程只能一直等待,等待获取锁的线程释放锁,而释放锁的情况只有当获取锁的线程执行完毕或者对应的线程发生异常;因此需要一种机制,可以不让等待的线程一直无限期的等待,而Lock就可以完成
Lock的主要特点
- 可以知道线程有没有成功获取到锁
- 多个线程都只是进行读操作时,线程之间不会发生冲突
- 尝试去拿锁,如果拿不到锁,则等待一段时间,在时间期限范围内,如果还拿不到锁,则返回false;如果期限范围内或者一开始就拿到锁则返回true
- 当通过lockInterruptibly()方法获取锁时,如果线程正在等待获取锁,这个线程可以相应中断,即中断线程的等待状态
上面的四个有点也就是Lock接口的四个方法
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
Condition newCondition();
void unlock();
}
注意事项:
- synchronized锁定的线程代码执行完之后自动释放锁,而Lock用户必须手动通过unlock()方法释放锁
- synchronized是内置关键字,而Lock是通过这个类实现同步访问
Lock的代码示例
java.util.concurrent.locks.ReentrantLock是唯一实现Lock接口的类
private void fun() {
Lock lock = new ReentrantLock();
lock.lock();
try {
//处理任务
}catch (Exception exception){
//处理异常
}finally {
//释放锁
lock.unlock();
}
}
- lock()方法同synchronized关键字功能一样,都是获取锁,如果锁已被其它线程获取,则进行等待。需要注意的是,涉及lock的获取锁,Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生.
private void fun() {
Lock lock = new ReentrantLock();
if(lock.tryLock()){
try {
//处理任务
}catch (Exception exception){
}finally {
//释放锁
lock.unlock();
}
}else {
//如果没有获取到锁,则做其它事情
}
}
- tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待
- tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true
private void fun() {
Lock lock = new ReentrantLock();
try {
lock.lockInterruptibly();
//处理任务
} catch (InterruptedException e) {
//中断异常处理
} finally {
//释放锁
lock.unlock();
}
}
- lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程
ReadWriteLock的代码示例
java.util.concurrent.locks.ReadWriteLock是一个读写锁
public interface ReadWriteLock {
/**
* Returns the lock used for reading.
*
* @return the lock used for reading
*/
Lock readLock();
/**
* Returns the lock used for writing.
*
* @return the lock used for writing
*/
Lock writeLock();
}
- 一个用来获取读锁,一个用来获取写锁。也就是说将文件的读写操作分开,分成2个锁来分配给线程,从而使得多个线程可以同时进行读操作。
- java.util.concurrent.locks.ReentrantReadWriteLock是唯一实现ReadWriteLock的类
public class ReadWriteLockTest {
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void get(Thread thread) {
Lock readLock = readWriteLock.readLock();
try {
readLock.lock();
System.out.println(thread.getName() + "读操作开始");
Thread.sleep(2000);
System.out.println(thread.getName() + "读操作完毕");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
}
}
ReadWriteLockTest lockTest = new ReadWriteLockTest();
new Thread(new Runnable() {
@Override
public void run() {
lockTest.get(Thread.currentThread());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
lockTest.get(Thread.currentThread());
}
}).start();
//运行结果
Thread-0读操作开始
Thread-1读操作开始
Thread-1读操作完毕
Thread-0读操作完毕
- 读写锁中的读操作锁互不干涉,可以有多个线程同时进行读锁内的操作,大大提高读操作的速度
public class ReadWriteLockTest {
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void get(Thread thread) {
Lock readLock = readWriteLock.writeLock();
try {
readLock.lock();
System.out.println(thread.getName() + "写操作开始");
Thread.sleep(2000);
System.out.println(thread.getName() + "写操作完毕");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
}
}
ReadWriteLockTest lockTest = new ReadWriteLockTest();
new Thread(new Runnable() {
@Override
public void run() {
lockTest.get(Thread.currentThread());
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
lockTest.get(Thread.currentThread());
}
}).start();
//运行结果
Thread-0写操作开始
Thread-0写操作完毕
Thread-1写操作开始
Thread-1写操作完毕
- 读写锁中的写操作,保证了多个线程运行时,只有一个线程在进行写操作
public static class ReadLock implements Lock, java.io.Serializable {
/**
* Acquires the read lock.
*
* <p>Acquires the read lock if the write lock is not held by
* another thread and returns immediately.
*
* <p>If the write lock is held by another thread then
* the current thread becomes disabled for thread scheduling
* purposes and lies dormant until the read lock has been acquired.
*/
public void lock() {
sync.acquireShared(1);
}
}
public static class WriteLock implements Lock, java.io.Serializable {
/**
* Acquires the write lock.
*
* <p>Acquires the write lock if neither the read nor write lock
* are held by another thread
* and returns immediately, setting the write lock hold count to
* one.
*
* <p>If the current thread already holds the write lock then the
* hold count is incremented by one and the method returns
* immediately.
*
* <p>If the lock is held by another thread then the current
* thread becomes disabled for thread scheduling purposes and
* lies dormant until the write lock has been acquired, at which
* time the write lock hold count is set to one.
*/
public void lock() {
sync.acquire(1);
}
}
- 不过要注意的是,如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。
- 如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,则申请的线程会一直等待释放写锁。
本文地址:https://blog.csdn.net/qq_30359699/article/details/107272832
上一篇: 香港月饼种类,带你去品味好吃的港式月饼
下一篇: java-EE学习记录——个人学习记录