个人笔记 Java多线程(七)

这段笔记是参照b站教程BV1Rv411y7MU整理而来的,用于个人备忘以便复习,需要的朋友可以自取。

Lock显示锁

在JDK5中增加了LOCK锁接口,有ReetrantLock实现类,ReetranLock实现类,它的功能比synchronized多。

锁的可重入性

锁的可重入性指,当一个线程获得了一个锁对象后,它再次请求该对象锁是可以获得该对象锁的。

ReentrantLock

ReentrantLock的基本使用

调用lock()方法,调用unlock()方法释放锁。

位于lock()于unlock()之间的代码相当于同步代码块

ReentrantLock基本使用
public class ReentrantLockTest {
    //定义显示锁
    static Lock lock = new ReentrantLock();

    public static void sm(){

        lock.lock();
        //for循环就是同步代码块
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+" -- "+i);
        }
        lock.unlock();
    }

    public static void main(String[]args){
        Runnable r = new Runnable() {
            @Override
            public void run() {
                sm();
            }
        };

        new Thread(r).start();
        new Thread(r).start();
        new Thread(r).start();
    }
}

使用lock锁同步不同的同步代码块
/**
 * 使用lock锁同步不同的同步代码块
 */
public class Test01 {

     private static Lock lock = new ReentrantLock();
    public static void sm1(){
        //Lock锁获得后,经常在finally子句中释放锁
        try{
            lock.lock();//打开锁
            System.out.println(Thread.currentThread().getName()+" -- "+ System.currentTimeMillis());
            Thread.sleep((int) (Math.random()*1000));
            System.out.println(Thread.currentThread().getName()+" -wake1- "+ System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();//释放锁
        }
    }

    public static void sm2(){
        try{
            lock.lock();
            System.out.println(Thread.currentThread().getName()+" -- "+System.currentTimeMillis());
            Thread.sleep((int)(Math.random()*1000));
            System.out.println(Thread.currentThread().getName()+" -wake2- "+ System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[]args){
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                sm1();
            }
        };
        Runnable r2 = new Runnable() {
            @Override
            public void run() {
                sm2();
            }
        };
        new Thread(r1).start();
        new Thread(r1).start();
        new Thread(r1).start();
        new Thread(r2).start();
        new Thread(r2).start();
        new Thread(r2).start();
    }
}

ReentrantLock可重入性

锁的可重入性指的是一个锁对象可以被反复获得,在一个线程中一般锁的获得在try中释放在finally中,重复获得几次锁,finally中就要释放几次锁

反复获得的锁必须是同一锁对象!

public class Test02 {

    private final static Lock lock=new ReentrantLock();

    public static class SubThread extends Thread{

        public static int num = 0;//定义变量
        @Override
        public void run() {
            for (int i = 0; i < 100000; i++) {
                //可重入锁指可以反复获得该锁
                //但是try中获得几次finally中就要释放几次
                try{
                    lock.lock();
                    num++;
                }finally {
                    lock.unlock();
                }
            }
        }
    }

    public static void main(String[]args) throws InterruptedException {
        SubThread s1 = new SubThread();
        SubThread s2 = new SubThread();
        s1.start();
        s2.start();
        s1.join();
        s2.join();
        System.out.println(SubThread.num);
    }
}

lockInterruptibly()

lockInterruptibly()方法的作用:如果当前线程未被中断则获得锁,如果当前线程被中断就抛出异常。

下述代码中使用lockInterruptibly()方法,正常使用synchronized同步代码块或者使用lock()的时候,线程调用interrupt()方法只会给线程打上停止标签,并不会立刻中断线程。

而lockInterruptibly()方法捕获到interrupt标签之后立刻中止线程抛出异常,并跳转到finally语句。

/**
 * lockInterruptibly()方法作用:如果当前线程未被中断则获得锁,如果当前线程被中断则抛出异常
 */
public class lockInterruptiblyTest {

    public static class Service{
        private final Lock lock = new ReentrantLock();
        public void serviceMethod(){
            try{
                //lock.lock();
                lock.lockInterruptibly();
                System.out.println(Thread.currentThread().getName()+" -- begin lock");

                //执行一段很耗时的代码
                for (int i = 0; i < Integer.MAX_VALUE; i++) {
                    new StringBuilder();
                }
                System.out.println(Thread.currentThread().getName()+" -- end lock");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName()+" -- over");
                lock.unlock();
            }
        }
    }

    public static void main(String[]args) throws InterruptedException{
        Service service = new Service();

        Runnable r = new Runnable() {
            @Override
            public void run() {
                service.serviceMethod();
            }
        };

        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);

        t1.start();
        Thread.sleep(50);
        t2.start();
        Thread.sleep(50);
        t2.interrupt();
    }
}

对于一个内部所来说,如果一个线程在等待锁,那么只有两个结果:

  1. 要么线程获得锁继续执行
  2. 要么线程保持等待

对于ReentrantLock可重入锁来说,它提供了另一种可能:在等待锁的过程中,程序可以根据需要取消对锁的请求

public class Test03 {
    public static void main(String[] args) throws InterruptedException {
        IntLock intLock1 = new IntLock(11);
        IntLock intLock2 = new IntLock(22);

        Thread t1 = new Thread(intLock1);
        Thread t2 = new Thread(intLock2);

       t1.start();
       t2.start();

       //等待3s,如果还有线程没有结束就中断该线程
       Thread.sleep(3000);


       //正常情况下中断一个线程来解决死锁
        /*
       if(t1.isAlive()){
           t1.interrupt();
       }
         */
       if(t2.isAlive()){
           t2.interrupt();
       }

    }

    static class IntLock implements Runnable{

        private final static ReentrantLock lock1 = new ReentrantLock();
        private final static ReentrantLock lock2 = new ReentrantLock();
        private final int LockNum;//定义变量,决定使用哪个锁

        public IntLock(int num){
            this.LockNum=num;
        }

        @Override
        public void run() {

            try{
                if(this.LockNum % 2 ==1) {
                    //奇数
                    lock1.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName() + " -- 获得锁1,还需要获得锁2");
                    Thread.sleep((int) (Math.random() * 1000));
                    lock2.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName() + " -- 获得了锁1和锁2");
                }else {
                    //偶数
                    lock2.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName()+" -- 获得锁2,还需要获得锁1");
                    Thread.sleep((int)(Math.random()*1000));
                    lock1.lockInterruptibly();
                    System.out.println(Thread.currentThread().getName()+" -- 获得了锁2和锁1");
                }
            }catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if(lock1.isHeldByCurrentThread())
                    lock1.unlock();
                if(lock2.isHeldByCurrentThread())
                    lock2.unlock();
                System.out.println(Thread.currentThread().getName()+" -- 已释放所有锁");

            }
        }
    }
}

tryLock()方法的使用

tryLock(Long time,timeUnit unit)的作用为在等待时长内锁没有被另外的线程持有,并且当前线程也没有被中断,则获得该锁。该方法可以实现锁对象的显示等待。

下述代码中,如果Thread-0先获得了锁,并且需要执行任务4s,在此期间,3s的时候Thread-1尝试获得锁,但是此时Thread-0还未释放锁,所以此时Thread-1申请锁失败。

public class tryLockTest {

    public static class TimeLock implements Runnable{

        private final static ReentrantLock lock = new ReentrantLock();

        @Override
        public void run() {
            try {
                //获得锁并返回true
                if(lock.tryLock(3, TimeUnit.SECONDS)){
                    System.out.println(Thread.currentThread().getName()+" -- 获得锁");
                    Thread.sleep(4000);
                }else{
                    //没有获得锁
                    System.out.println(Thread.currentThread().getName()+" -- 没有获得锁");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                if (lock.isHeldByCurrentThread())
                    lock.unlock();
            }

        }
    }

    public static void main(String[] args) {
        TimeLock timeLock = new TimeLock();

        Thread t1 = new Thread(timeLock);
        Thread t2 = new Thread(timeLock);
        t1.start();
        t2.start();
    }
}

tryLock()【无参数】仅在调用时锁定未被其他线程持有的锁,如果调用其他方法,锁对象被其他线程持有,则放弃。即无参数情况下,如果当前锁没有被其他线程占用就执行,否则就不执行返回false不等待

通过tryLock()可以避免死锁。
原理是tryLock()请求锁,如果锁正被占用就返回false并不在请求。利用while循环不断执行这一操作最终肯定会被请求到。
下述代码的含义是: 以偶数情况为例,假设Thread-0线程第一次tryLock()的时候,此时lock1、lock2均为被占用,所以Thread-0和Thread-1都可以请求到,但是第二个try语句的时候,Thread-0开始请求lock2锁,但是此时lock2被Thread-1占用,所以tryLock()请求失败,返回false,并执行finally语句,由于没有请求到lock2,所以此时isHeldByCurrentThread()当前持有线程不是lock2,所以直接跳过finally代码块,此时外层try也结束进入到外层finally代码块,判断当前持有线程为lock1的时候释放锁。Thread-1步骤同理。
这个时候其中睡眠时间是随机数,所以什么时候一个线程可以同时请求到两个锁完全看运气,将两个时间设置为固定值会大大减缓尝试时间。

public class Test04 {

    public static class IntLock implements Runnable{

        private final static ReentrantLock lock1 = new ReentrantLock();
        private final static ReentrantLock lock2 = new ReentrantLock();
        private int num;

        public IntLock(int num){
            this.num = num;
        }

        @Override
        public void run() {
            if(this.num % 2 == 0){
                //偶数
                while(true){
                    try{
                        if(lock1.tryLock()){
                            System.out.println(Thread.currentThread().getName()+" -- 获得了锁1,还需获得锁2");
                            Thread.sleep((int)(Math.random()*1000));
                            try{
                                if (lock2.tryLock()){
                                    System.out.println(Thread.currentThread().getName()+" -- 同时获得了锁1和锁2");
                                    return;//完成任务,退出run方法,即当前线程结束
                                }
                            }finally {
                                if(lock2.isHeldByCurrentThread())
                                    lock2.unlock();
                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        if(lock1.isHeldByCurrentThread())
                            lock1.unlock();
                    }
                }
            }else{
                //奇数
                while(true){
                    try{
                        if(lock2.tryLock()){
                            System.out.println(Thread.currentThread().getName()+" --获得了锁2,还需获得锁1");
                            Thread.sleep((int)(Math.random()*1000));
                            try{
                                if(lock1.tryLock()){
                                    System.out.println(Thread.currentThread().getName()+" -- 同时获得了锁2和锁1");
                                    return;
                                }
                            }finally {
                                if(lock1.isHeldByCurrentThread())
                                    lock1.unlock();
                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        if(lock2.isHeldByCurrentThread())
                            lock2.unlock();
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        IntLock intLock1 = new IntLock(11);
        IntLock intLock2 = new IntLock(22);

        Thread t1 = new Thread(intLock1);
        Thread t2 = new Thread(intLock2);

        /**
         * 运行后,使用tryLock()后线程如果没有获得锁,
         * 那么while就会进行下一次循环会不断重复请求,
         * 最终一定会请求到,所以可以避免死锁
         */
        t1.start();
        t2.start();
    }
}

new Condition()方法

关键子synchronized与wait()/notify()一起使用可以实现等待通知模式。Lock的锁的new Condition()方法返回Condition对象,Condition类也可以实现等待/通知模式。

使用notify()通知的时候,JVM会随机唤醒某个等待的线程,使用Condition类的可以进行选择性通知。

Condition常用的两个方法:

  1. await()会使得当前线程等待,同时会释放锁。当其他线程调用signal()时,线程会重新获得锁并继续执行。
  2. signal()用于唤醒一个等待线程。
    注意:在调用Condition的await()/signal()方法之前,也需要线程持有相关的Lock锁。调用await()之后线程会释放锁,调用signal()调用后会从当前condition对象的等待队列中唤醒一个线程,唤醒的线程会尝试获得锁,一旦获得锁成功就继续执行。

await()进入等待状态同样会释放锁,此时唤醒要申请锁。调用signal()方法的时候必须获得锁(同一把锁),所以在main方法中调用signal()的时候要在同步代码块中运行。

public class conditionTest {

    //定义锁
    public static final ReentrantLock Lock = new ReentrantLock();

    //定义Condition对象
    public static Condition condition = Lock.newCondition();

    //定义线程子类
    public static class SubThread extends Thread {
        @Override
        public void run() {
            try {
                Lock.lock();
                System.out.println("lock method...");
                condition.await();
                System.out.println("await method...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                Lock.unlock();
                System.out.println("unlock method...");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SubThread t1 = new SubThread();

        t1.start();
        Thread.sleep(3000);
        try{
            Lock.lock();
            condition.signal();
        }finally {
            Lock.unlock();
        }
    }
}

通知部分线程

public class conditionTest {
    static class Service{
        //定义锁
        public static final ReentrantLock Lock = new ReentrantLock();

        //定义Condition对象
        public static Condition conditionA = Lock.newCondition();
        public static Condition conditionB = Lock.newCondition();

        //定义方法
        public void waitMethodA(){
            try{
                Lock.lock();
                System.out.println(Thread.currentThread().getName()+" -- begin wait: "+System.currentTimeMillis());
                conditionA.await();
                System.out.println(Thread.currentThread().getName()+" -- end wait: "+System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                Lock.unlock();
            }
        }

        public void waitMethodB(){
            try{
                Lock.lock();
                System.out.println(Thread.currentThread().getName()+" -- begin wait: "+System.currentTimeMillis());
                conditionB.await();
                System.out.println(Thread.currentThread().getName()+" -- end wait: "+System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                Lock.unlock();
            }
        }

        public void signalA(){
            try{
                Lock.lock();
                System.out.println(Thread.currentThread().getName()+" 开始唤醒A "+System.currentTimeMillis());
                conditionA.signal();
                System.out.println(Thread.currentThread().getName()+" 开始唤醒A结束 "+System.currentTimeMillis());
            }finally {
                Lock.unlock();
            }
        }

        public void signalB(){
            try{
                Lock.lock();
                System.out.println(Thread.currentThread().getName()+" 开始唤醒B "+System.currentTimeMillis());
                conditionB.signal();
                System.out.println(Thread.currentThread().getName()+" 开始唤醒B结束 "+System.currentTimeMillis());
            }finally {
                Lock.unlock();
            }
        }
    }


    public static void main(String[] args) throws InterruptedException {
        Service service = new Service();

        new Thread(new Runnable() {
            @Override
            public void run() {
                service.waitMethodA();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                service.waitMethodB();
            }
        }).start();
        Thread.sleep(3000);
        //唤醒conditionA
        service.signalA();
        Thread.sleep(3000);
        service.signalB();

    }
}

实现两个线程交替打印

主要时修改打印标志,一个线程打印的时候另一个线程设为等待,以此循环。

下述代码打印的时候,第一段解读尤为重要。首先第一次循环Thread-0和THread-1同时开始,但是此时Thread-0(也可能时Thread-1)先获得CPU执行权,所以先进行printOne的判断,这个时候Thread进入await状态,释放锁,这个时候Thread-1得以进入,判断打印之后释放锁,此时Thread-1仍然持有CPU执行权,继续执行for循环,第二次循环的时候条件不满足,因此释放锁进入等待并通知唤醒Thread-0,此后两个线程变依次循环直到100次打印完成。

public class Test05 {
    public static class Service{
        private static final ReentrantLock Lock = new ReentrantLock();
        private final Condition condition = Lock.newCondition();
        private boolean flag = true;

        public void printOne(){
            try{
                Lock.lock();
                //flag为true等待
                while (this.flag){
                    System.out.println("one wait...");
                    condition.await();
                }
                //flag为false打印
                System.out.println(Thread.currentThread().getName()+" -- ----------");
                this.flag = true;
                condition.signal();//通知另外的线程打印
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                Lock.unlock();
            }
        }

        public void printTwo(){
            try{
                Lock.lock();
                //flag为false的时候等待
                while(!this.flag){
                    System.out.println("two wait...");
                    condition.await();
                }
                //flag为true的时候打印
                System.out.println(Thread.currentThread().getName()+" -- *************");
                this.flag = false;
                condition.signal();//通知其他线程打印
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                Lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        Service service = new Service();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("one: "+i);
                    service.printOne();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println("two: "+i);
                    service.printTwo();
                }
            }
        }).start();
    }
}

公平锁与非公平锁

大多数情况下,锁的申请都是非公平的,如果线程1和线程2都在申请锁A,当锁A可用的时候,系统只是从阻塞队列中随机选择一个线程,不能保证其公平性。

公平锁会按照时间先后顺序,保证先到先得,公平锁这一特点不会出现线程饥饿线程。

synchronized内部所就是非公平的,而ReentrantLock重入锁提供了一个构造方法ReentrantLock(boolean fair),在创建锁对象的时候,实参传递true就可以创建公平锁。

非公平锁系统倾向让已经获得过该锁的程序再次获得锁,这是高效的,但是是非公平的。

如果是公平锁,系统不会发生让同一个线程连续多次获得锁的可能以保证公平。

公平锁看起来很公平,但是要实现公平锁,必须要系统维护一个有序队列,所以公平锁的实现成本相对较高,性能也低。因此默认情况下锁是非公平的。不是特别需求一般不使用公平锁。


几个常用方法 ReentrantLock实例方法
  1. int getHoldCount()可以返回当前线程调用方法的次数(记录调用lock()的次数)
  2. int getQueueLength()可以返回正等待锁的预估数(不准确,可能有误差)
  3. int getWaitQueueLength(Conditon 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()查询当前锁是否被线程持有

ReentrantReadWriteLock 读写锁

synchronzied和ReentrantLock都是独占锁(排他锁),同一时间只能由一个线程持有并执行同步代码块,可以保证线程的安全性,但是执行效率低。

ReentrantReadWriteLock读写锁是一种改进的排他锁,也可以成为共享/排他锁,它允许多个线程同时读取共享数据,但是一次只允许一个线程对共享数据进行更新。

读写锁通过读锁与写锁来完成读写操作线程在操作共享数据前必须先持有读锁,该读锁可以被多个线程持有,即它是共享的

**线程在修改共享数据前必须先持有写锁,写锁是排他的。**一个线程持有写锁的时候,其他线程无法获得相应的锁。

**读锁只是在读线程之间共享,任何一个线程持有读锁的时候,其他线程都无法获得写锁。**读数据的时候大家一起读,没有人可以写。写数据的时候只有一个人写。这样可以保障线程在读取数据的时候没有其他线程对数据进行更新,使得线程能够读到数据的最新值,保证读取数据期间共享变量不会被修改

获得条件排他性作用
读锁写锁未被任意线程占有对读线程共享的,
对写线程是排他的
允许多个读线程可以同时读取共享数据,保证读取共享数据的同时没有其他线程对共享数据进行修改
写锁该写锁未被其他线程持有,
其相应的读锁也未被其他线程持有
对读线程或者写线程都是排他的保证写线程以独占的形式修改共享数据

读写锁允许读读共享,读写互斥,写写互斥。

java.util.concurrent.locks包中定义了ReadWriteLock接口,该接口定义了readLock()返回读锁 ,writeLock()返回写锁。该接口的实现类是ReentrantReadWriteLock

注意readLock()和 writeLock()方法返回的锁对象是同一个锁的两个不同角色,不是分别获得两个锁!

//定义读写锁
ReadWriteLock rwLock = new ReentrantReadWriteLock();

//获得读锁
Lock readLock = rwLock.readLock();

//获得写锁
Lock writeLock = rwLock.writeLock();

//读数据的方法
try{
    readLock.lock()
    ......
}finally{
    readLock.unlock();
}

//写数据的方法
try{
    writeLock.lock();
}finally{
    writeLock.unlock();
}

读读共享

ReadWriteLock读写锁可以实现多个线程同时读取共享数据,即读读共享,可以提高程序的读取数据的效率。

public class ReentrantReadWriteLockTest {
    static class Service{
        //定义读写锁
        private final static ReadWriteLock rwLock = new ReentrantReadWriteLock();
        //读锁
        private final Lock readLock = rwLock.readLock();
        //写锁
        private final Lock writeLock = rwLock.writeLock();

        public void read(){
            try{
                this.readLock.lock();
                System.out.println(Thread.currentThread().getName()+" -- 获得读锁的时间: "+System.currentTimeMillis());
                TimeUnit.SECONDS.sleep(3);//模拟读取时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName()+" -- 释放读锁: "+System.currentTimeMillis());
                this.readLock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        Service service = new Service();

        //创建5个线程
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    service.read();
                }
            }).start();
        }
    }

}

写写互斥

通过ReadWriteLock读写锁中的写锁,只允许有一个线程执行lock()后面的代码。
同一时间只有一个线程获得写锁。

public class Test {
    static class Service{
        private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
        private final Lock writeLock = rwLock.writeLock();

        public void write(){
            try{
                writeLock.lock();
                System.out.println(Thread.currentThread().getName()+" -- 获得写锁,开始修改数据! "+System.currentTimeMillis());
                Thread.sleep(3000);//模拟修改数据的用时
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName()+" == 修改数据完毕 == "+System.currentTimeMillis());
                writeLock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        Service service = new Service();
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    service.write();
                }
            }).start();
        }
    }
}

读写互斥

写锁是独占锁,是排他锁,读线程与写线程也是互斥的
下例代码中写锁会在读锁完成之后在允许。

public class Test01 {
    public static class Service{
        private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
        private final Lock readLock = rwLock.readLock();
        private final Lock writeLock = rwLock.writeLock();

        public void read(){
            try{
                readLock.lock();
                System.out.println(Thread.currentThread().getName()+" -- Read Lock..."+System.currentTimeMillis());
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName()+" -- Read Unlock..."+System.currentTimeMillis());
                readLock.unlock();
            }
        }

        public void write(){
            try{
                writeLock.lock();
                System.out.println(Thread.currentThread().getName()+" == Write Lock..."+System.currentTimeMillis());
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName()+" == Write Unlock..."+System.currentTimeMillis());
                writeLock.unlock();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Service service = new Service();

        //定义一个线程读数据
        new Thread(new Runnable() {
            @Override
            public void run() {
                service.read();
            }
        }).start();
        //定义一个线程写数据
        new Thread(new Runnable() {
            @Override
            public void run() {
                service.write();
            }
        }).start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值