Java并发编程锁的分类-以及读写锁的实例

1.可重入锁:

              1)概念:锁具备可重入性,则称为可重入锁;可重入性表明了锁的分配机制,是基于线程分配的,而不是基于方法调用分配的;

              2):synchronized 和 ReentrantLock都是属于可重入锁

              3):举例说明

class ReentrantLockClass{
        //当某个线程A申请到methodOne()方法的锁,执行methodOne()方法,这时该对象被锁住
        //在methodOne()方法中调用了methodTwo()方法,methodTwo()也是需要申请锁资源的
        //此时如果线程A仍然需要申请锁资源才能执行methodTwo()方法,则线程A则会无线等待下去
        //因为这个对象的所资源已被线程A申请methodOne()方法的锁锁住
        //但是我们在实际情况下是不会发生这种情况的,所以synchronized是可重入锁
        public synchronized void methodOne(){
            //处理业务
            methodTwo();
            //处理业务
        }

        public synchronized void methodTwo(){
            //处理业务
        }
}

2.公平锁和非公平锁

          1).公平锁:尽可能的按照申请锁资源的顺序执行,当同时有多个线程等待一个锁时,这个锁被释放掉,则等待锁资源时间最长的线程,获得该锁权限

          2).非公平锁:无法保证线程的执行顺序是按照申请锁资源的顺序执行的,可能导致某个或者一些线程永远获取不到锁

          3).synchronized 是非公平锁 

              ReentrantLock 默认是非公平锁,即通过无参构造函数创建的 ,可以通过有参的构造函数创建公平锁

             ReentrantReadWriteLock 默认是非公平锁,即通过无参构造函数创建的 ,可以通过有参的构造函数创建公平锁

3.读写锁ReentrantReadWriteLock

     1) 通过synchronized实现读锁

package com.roger.juc;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriterLockMain {

    public synchronized void readFile() throws Exception{
        long startTime = System.currentTimeMillis();
        System.out.println("开始执行时间-startTime = " + startTime);
        for(int i=0; i < 5; i++){
            Thread.sleep(20);
            System.out.println(Thread.currentThread().getName() + "正在读取文件信息....");
        }
        System.out.println(Thread.currentThread().getName() + "读取完毕");
        long endTime = System.currentTimeMillis();
        System.out.println("结束时间-endTime = " + endTime);
    }

    public static void main(String[] args) {
        final ReadWriterLockMain readWriterLockMain = new ReadWriterLockMain();

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    readWriterLockMain.readFile();
                } catch (Exception e) {

                }
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    readWriterLockMain.readFile();
                } catch (Exception e) {

                }
            }
        });

        thread1.start();
        thread2.start();
    }

}

          执行结果:

开始执行时间-startTime = 1542781854228
Thread-0正在读取文件信息....
Thread-0正在读取文件信息....
Thread-0正在读取文件信息....
Thread-0正在读取文件信息....
Thread-0正在读取文件信息....
Thread-0读取完毕
结束时间-endTime = 1542781854330
开始执行时间-startTime = 1542781854330

Thread-1正在读取文件信息....
Thread-1正在读取文件信息....
Thread-1正在读取文件信息....
Thread-1正在读取文件信息....
Thread-1正在读取文件信息....
Thread-1读取完毕
结束时间-endTime = 1542781854432

          结论:通过synchronized实现读锁,是互斥的,只有线程Thread-0执行完成后,Thread-1线程才能执行

          2)通过ReentrantReadWriteLock实现读锁

package com.roger.juc;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriterLockMain {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void readFile(){
        //添加读锁
        lock.readLock().lock();
        try {
            long startTime = System.currentTimeMillis();
            System.out.println("开始执行时间-startTime = " + startTime);
            for(int i=0; i < 5; i++){
                Thread.sleep(20);
                System.out.println(Thread.currentThread().getName() + "正在读取文件信息....");
            }
            System.out.println(Thread.currentThread().getName() + "读取完毕");
            long endTime = System.currentTimeMillis();
            System.out.println("结束时间-endTime = " + endTime);
        }catch (Exception e){

        }finally {
            //释放读锁
            lock.readLock().unlock();
        }

    }

    public static void main(String[] args) {
        final ReadWriterLockMain readWriterLockMain = new ReadWriterLockMain();

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    readWriterLockMain.readFile();
                } catch (Exception e) {

                }
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    readWriterLockMain.readFile();
                } catch (Exception e) {

                }
            }
        });

        thread1.start();
        thread2.start();
    }

}

             执行结果:

开始执行时间-startTime = 1542782940771
开始执行时间-startTime = 1542782940772

Thread-0正在读取文件信息....
Thread-1正在读取文件信息....
Thread-0正在读取文件信息....
Thread-1正在读取文件信息....
Thread-0正在读取文件信息....
Thread-1正在读取文件信息....
Thread-0正在读取文件信息....
Thread-1正在读取文件信息....
Thread-0正在读取文件信息....
Thread-0读取完毕
结束时间-endTime = 1542782940871
Thread-1正在读取文件信息....
Thread-1读取完毕
结束时间-endTime = 1542782940872

            结论:ReentrantReadWriteLock的读锁是可以共享的,执行效率明显高于synchronized

            3)ReentrantReadWriteLock的读锁和写锁

package com.roger.juc;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriterLockMain {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void readFile(){
        //添加读锁
        lock.readLock().lock();
        boolean readLock = lock.isWriteLocked();
        if(!readLock){
            System.out.println("当前为读锁");
        }
        try {
            long startTime = System.currentTimeMillis();
            System.out.println("开始执行时间-startTime = " + startTime);
            for(int i=0; i < 5; i++){
                Thread.sleep(20);
                System.out.println(Thread.currentThread().getName() + "正在读取文件信息....");
            }
            System.out.println(Thread.currentThread().getName() + "读取完毕");
            long endTime = System.currentTimeMillis();
            System.out.println("结束时间-endTime = " + endTime);
        }catch (Exception e){

        }finally {
            System.out.println("释放读锁");
            lock.readLock().unlock();
        }

    }

    public void writeFile(){
        //添加写锁
        lock.writeLock().lock();
        boolean writeLock = lock.isWriteLocked();
        if(writeLock){
            System.out.println("当前为写锁");
        }
        try {
            long startTime = System.currentTimeMillis();
            System.out.println("开始执行时间-startTime = " + startTime);
            for(int i=0; i < 5; i++){
                Thread.sleep(20);
                System.out.println(Thread.currentThread().getName() + "正在写文件信息....");
            }
            System.out.println(Thread.currentThread().getName() + "写完毕");
            long endTime = System.currentTimeMillis();
            System.out.println("结束时间-endTime = " + endTime);
        }catch (Exception e){

        }finally {
            System.out.println("释放写锁");
            lock.writeLock().unlock();
        }

    }
    public static void main(String[] args) {
        final ReadWriterLockMain readWriterLockMain = new ReadWriterLockMain();

        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                readWriterLockMain.readFile();
            }
        });

        executorService.execute(new Runnable() {
            @Override
            public void run() {
                readWriterLockMain.writeFile();
            }
        });
    }

}

           执行结果:

当前为读锁
开始执行时间-startTime = 1542783555994
pool-1-thread-1正在读取文件信息....
pool-1-thread-1正在读取文件信息....
pool-1-thread-1正在读取文件信息....
pool-1-thread-1正在读取文件信息....
pool-1-thread-1正在读取文件信息....
pool-1-thread-1读取完毕
结束时间-endTime = 1542783556096
释放读锁
当前为写锁
开始执行时间-startTime = 1542783556096
pool-1-thread-2正在写文件信息....
pool-1-thread-2正在写文件信息....
pool-1-thread-2正在写文件信息....
pool-1-thread-2正在写文件信息....
pool-1-thread-2正在写文件信息....
pool-1-thread-2写完毕
结束时间-endTime = 1542783556198
释放写锁

        结论:ReentrantReadWriteLock的读锁和写锁时互斥,

                也就说如果一个线程已经占用了对象的读锁,那么其他线程想获取到这个对象的写锁,则需要等待

占用读锁的线程释放读锁之后,才能执行写操作;

                当一个线程已经占用了对象的写锁,那么其他线程想获取到这个对象的读锁或者写锁,则需要等待

占用写锁的线程释放写锁之后,才能执行相应的操作

猜你喜欢

转载自blog.csdn.net/lihongtai/article/details/84317874