您的位置:首页 > 编程语言 > Java开发

Java多线程核心技术(四):Lock的使用

2017-02-28 14:43 429 查看

一、使用ReentrantLock类

1、ReentrantLock的简单使用

代码示例:

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

class MyService{
private Lock lock = new ReentrantLock();
public void methodA(){
try{
lock.lock();
System.out.println("methodA begin ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodA end ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis());
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
public void methodB(){
try{
lock.lock();
System.out.println("methodB begin ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodB end ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis());
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
class ThreadA extends Thread{
private MyService service;
public ThreadA(MyService service){
this.service = service;
}
@Override
public void run(){
service.methodA();
}
}
class ThreadB extends Thread{
private MyService service;
public ThreadB(MyService service){
this.service = service;
}
@Override
public void run(){
service.methodB();
}
}
public class TestClass{
public static void main(String[] args){
MyService service = new MyService();
ThreadA a = new ThreadA(service);
a.setName("A");
ThreadA aa = new ThreadA(service);
aa.setName("AA");
ThreadB b = new ThreadB(service);
b.setName("B");
ThreadB bb = new ThreadB(service);
bb.setName("BB");
a.start();
aa.start();
b.start();
bb.start();
}
}

2、使用Condition实现等待/通知

关键字synchronized与wait()/notify()/notifyAll()方法相结合可以实现等待/通知模式,类ReetrantLock也可以实现同样的功能,但需要借助Condition对象。Condition类可以实现多路通知功能,也就是一个Lock对象里面可以创建多个Condition实例,线程对象可以注册在指定的Condition中,从而可以有选择性地进行线程通知,在调度线程上更灵活。

下面是使用多个Condition实现通知部分线程:

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

class MyService{
private Lock lock = new ReentrantLock();
public Condition conditionA = lock.newCondition();
public Condition conditionB = lock.newCondition();
public void awaitA(){
try{
lock.lock();
System.out.println("awaitA begin ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis());
conditionA.await();
System.out.println("awaitA end ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis());
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
public void awaitB(){
try{
lock.lock();
System.out.println("awaitB begin ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis());
conditionB.await();
System.out.println("awaitB end ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis());
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
public void signalAll_A(){
try{
lock.lock();
System.out.println("signalAll_A ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis());
conditionA.signalAll();//唤醒所有在conditionA上等待的线程
}finally{
lock.unlock();
}
}
public void signalAll_B(){
try{
lock.lock();
System.out.println("signalAll_B ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis());
conditionB.signalAll();//唤醒所有在conditionA上等待的线程
}finally{
lock.unlock();
}
}
}
class ThreadA extends Thread{
private MyService service;
public ThreadA(MyService service){
this.service = service;
}
@Override
public void run(){
service.awaitA();
}
}
class ThreadB extends Thread{
private MyService service;
public ThreadB(MyService service){
this.service = service;
}
@Override
public void run(){
service.awaitB();
}
}
public class TestClass{
public static void main(String[] args) throws InterruptedException{
MyService service = new MyService();
ThreadA a = new ThreadA(service);
a.setName("A");
ThreadA aa = new ThreadA(service);
aa.setName("AA");
ThreadB b = new ThreadB(service);
b.setName("B");
ThreadB bb = new ThreadB(service);
bb.setName("BB");
a.start();
aa.start();
b.start();
bb.start();
Thread.sleep(3000);
service.signalAll_A();
}
}运行结果如下:



3、公平锁与非公平锁

锁Lock分为“公平锁”和“非公平锁”,公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。而非公平锁就是一种获得锁的抢占机制,是随机获得锁的。创建公平锁就是在ReentrantLock类的构造函数中传入true:Lock lock = new ReentrantLock(true);

4、ReentrantLock的几个方法

(1)getHoldCount()的作用是查询当前线程保持此锁定的个数,也就是调用lock()方法的次数。

(2)getQueueLength()的作用是返回正在等待获取此锁定的线程估计数。

(3)int getWaitQueueLength(Condition condition)的作用是返回等待与此锁定相关的给定条件Condition的线程估计数。

(4)boolean hasQueuedThread(Thread thread)的作用是查询指定的线程是否正在等待获取此锁定。

(5)boolean hasQueuedThreads()的作用是查询是否有线程正在等待获取此锁定。

(6)boolean hasWaiters(Condition condition)的作用是查询是否有线程正在等待与此锁定有关的condition条件。

(7)boolean isFair()的作用是判断是不是公平锁。

(8)boolean isHeldByCurrentThread()的作用是查询当前线程是否保持此锁定。

(9)boolean isLocked()的作用是查询此锁定是否由任意线程保持。

(10)void lockInterruptibly()的作用是:如果当前线程未被中断,则获取锁定,如果已经被中断则出现异常。

(11)boolean tryLock()的作用是,仅在调用时锁定未被另一个线程保持的情况下,才获取该锁定。

(12)boolean tryLock(long timeout,TimeUnit unit)的作用是,如果锁定在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定。

二、使用ReentrantReadWriteLock类

类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务。这样做虽然保证了实例变量的线程安全性,但效率很低。使用读写锁ReentrantReadWriteLock类可以解决这个问题。读写锁表示有两个锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也叫排他锁。也就是多个读锁之间不互斥,读锁和写锁互斥,写锁和写锁互斥。

如下是读锁和写锁的使用示例:

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

class MyService{
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void read(){
try{
lock.readLock().lock();
System.out.println("获得读锁 ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis());
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
lock.readLock().unlock();
}
}
public void write(){
try{
lock.writeLock().lock();
System.out.println("获得写锁 ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis());
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
lock.writeLock().unlock();
}
}
}
class ThreadA extends Thread{
private MyService service;
public ThreadA(MyService service){
this.service = service;
}
@Override
public void run(){
service.read();
}
}
class ThreadB extends Thread{
private MyService service;
public ThreadB(MyService service){
this.service = service;
}
@Override
public void run(){
service.write();
}
}
public class TestClass{
public static void main(String[] args) throws InterruptedException{
MyService service = new MyService();
ThreadA a = new ThreadA(service);
a.setName("A");
ThreadB b = new ThreadB(service);
b.setName("B");
a.start();
b.start();
}
}运行结果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息