Java多线程学习四 Lock的使用

2019-04-18  本文已影响0人  殷俊杰

一、 配合Condition使用

Condition的await()方法相当于Object的wait()方法,signal相当于notify,signalAll相当于notifyAll,且它们都必须在持有锁的时候才能调用。

public class MyService {
    private Lock lock=new ReentrantLock();
    private Condition condition=lock.newCondition();

    public void await(){
        try {
            System.out.println("wait begin"+System.currentTimeMillis());
            lock.lock();
            condition.await();
            System.out.println("wait end"+System.currentTimeMillis());
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void signal(){
        try {
            lock.lock();
            System.out.println("signal时间为:"+System.currentTimeMillis());
            condition.signal();
        }finally {
            lock.unlock();
        }
    }
}
public class MyThread extends Thread {
    private MyService myService;

    public MyThread(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.await();
    }
}

public class TestMain {
    public static void main(String[] args) throws InterruptedException {
        MyService myService=new MyService();
        MyThread myThread=new MyThread(myService);
        myThread.start();
        Thread.sleep(3000);
        myService.signal();
    }
}

如果在调用Condition的await方法没有持有锁的话会报异常,和调用Object的wait方法一样

    public void await(){
        try {
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.fullyRelease(AbstractQueuedSynchronizer.java:1723)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2036)
    at com.yjj.chapter04.test02_condition.MyService.await(MyService.java:29)
    at com.yjj.chapter04.test02_condition.MyThread.run(MyThread.java:18)

二、使用多个Condition通知部分线程

package com.yjj.chapter04.test03_condition2;

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

/**
 * @Description:
 * @Author: YinJunjie
 * @CreateDate: 2018/9/27 15:45
 * @Version: 1.0
 */
public class MyService {
    private Lock lock=new ReentrantLock();
    private Condition conditionA=lock.newCondition();
    private Condition conditionB=lock.newCondition();

    public void awaitA(){
        try {
            System.out.println("waitA begin"+System.currentTimeMillis());
            lock.lock();
            conditionA.await();
            System.out.println("waitA end"+System.currentTimeMillis());
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void awaitB(){
        try {
            System.out.println("waitB begin"+System.currentTimeMillis());
            lock.lock();
            conditionB.await();
            System.out.println("waitB end"+System.currentTimeMillis());
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void signalA(){
        try {
            lock.lock();
            System.out.println("signalA时间为:"+System.currentTimeMillis());
            conditionA.signal();
        }finally {
            lock.unlock();
        }
    }

    public void signalB(){
        try {
            lock.lock();
            System.out.println("signalB时间为:"+System.currentTimeMillis());
            conditionB.signal();
        }finally {
            lock.unlock();
        }
    }
}

public class MyThreadA extends Thread {
    private MyService myService;

    public MyThreadA(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.awaitA();
    }
}

public class MyThreadB extends Thread {
    private MyService myService;

    public MyThreadB(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.awaitB();
    }
}
    public static void main(String[] args) throws InterruptedException {
        MyService myService=new MyService();
        MyThreadA myThreadA =new MyThreadA(myService);
        MyThreadB myThreadB =new MyThreadB(myService);
        myThreadB.start();
        myThreadA.start();
        Thread.sleep(3000);
        myService.signalA();
        Thread.sleep(3000);
        myService.signalB();
    }

三、公平锁与非公平锁

公平锁:线程获取说的顺序是按照线程加锁的顺序来分配的,即先来先得FIFO先进先出顺序。
非公平锁:获取锁是随机的,由各线程抢夺,先来的不一定闲的,这个方式可能造成某些线程一直拿不到锁。
创建公平锁:Lock lock=new ReentrantLock(true)
非公平锁:Lock lock=new ReentrantLock(false)

四、Lock常用方法

  1. int getHoldCount()
    查询当前线程保持次锁定的个数,也就是调用lock()方法的次数
  2. int 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()
    成功获取了锁的情况下才会返回true,如果别的线程当前正持有锁,则会立即返回false
  12. boolean tryLock(long timeOut,TimeUnit unit)
    如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。
    ...省略好几个方法,去看jdk api吧

五、读写锁

public class MyService {
    private ReentrantReadWriteLock lock=new ReentrantReadWriteLock();

    public void read(){
        try {
            lock.readLock().lock();
            System.out.println(Thread.currentThread().getName()+"读啊读");
            Thread.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.readLock().unlock();
            System.out.println(Thread.currentThread().getName()+"读完了");
        }
    }

    public void write(){
            try {
                lock.writeLock().lock();
                System.out.println(Thread.currentThread().getName()+"写啊写");
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }finally {
                lock.writeLock().unlock();
                System.out.println(Thread.currentThread().getName()+"写完了");
            }
        }
}
public class ReadThread extends Thread {
    private MyService myService;

    public ReadThread(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.read();
    }
}
public class WriteThread extends Thread {
    private MyService myService;

    public WriteThread(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.write();
    }
}

读读不互斥

        MyService myService = new MyService();
        ReadThread readThread1 = new ReadThread(myService);
        ReadThread readThread2 = new ReadThread(myService);
        readThread1.setName("read1");
        readThread2.setName("read2");
        readThread1.start();
        readThread2.start();
read1读啊读
read2读啊读
read1读完了
read2读完了

读写互斥

        MyService myService=new MyService();
        ReadThread readThread=new ReadThread(myService);
        WriteThread writeThread=new WriteThread(myService);
        readThread.setName("read");
        writeThread.setName("write");
        readThread.start();
        writeThread.start();
read读啊读
read读完了
write写啊写
write写完了

写写互斥 略

注意:

ReentrantLock也是可重入的

上一篇下一篇

猜你喜欢

热点阅读