Java并发编程(七):ReadWriteLock读写锁与线程八锁

ReadWriteLock读写锁与线程八锁

场景

什么情况下采用读写锁?

  • 写写操作/读写操作 需要互斥
  • 读读操作 不需要互斥

如果都用独占锁,有时候很多读操作并发时其实并不需要锁住缺上了锁,导致效率低下,可以采用读写锁来代替:

import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class TestReadWriteLock {
    public static void main(String[] args)
    {
        ReadWriteLockDemo rw = new ReadWriteLockDemo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //等一下,让一些读线程先读
                    Thread.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 写一个 随机数
                rw.setNumber(new Random().nextInt(111));
            }
        },"Write:").start();

        // 起100个线程去读
        for(int i= 0;i<100;i++)
        {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    rw.getNumber();
                }
            },"Read:") .start();
        }

    }
}
class ReadWriteLockDemo{
    private  int number = 0;

    private ReadWriteLock lock = new ReentrantReadWriteLock();

    //读
    public void getNumber(){
        lock.readLock().lock();

        try{
            System.out.println(Thread.currentThread().getName()+":"
                    + number);
        }
        finally {
            lock.readLock().unlock();
        }

    }

    //写
    public void setNumber(int number)
    {
        lock.writeLock().lock();
        try
        {
            System.out.println(Thread.currentThread().getName());
            this.number = number;
        }
        finally {
            lock.writeLock().unlock();
        }

    }

}

代码逻辑:

  • 一个线程去写,稍微延迟一会,先让几个线程读一下
  • 100个线程去读

实际执行结果:

Read::0
Read::0
Read::0
Read::0
Write:
Read::23
Read::23
Read::23
Read::23
......//后面全是Read::23

刚开始写线程还没写,读线程先读了4个0,后面写锁抢占,写入了数据,释放锁

释放之后,其他读线程继续读,读到的都是23

解决的问题

用读写锁代替独占锁,提高了效率

线程八锁

看以下代码:

/**
 * 题目:判断打印的 "one" or "two"
 *
 * 1.两个普通同步方法,两个线程,标准打印 one two
 * 2.新增 Thread.sleep()方法给 getOne ,打印 one two
 * 3.新增 普通方法 getThree(),打印 three one two
 * 4.两个普通的同步方法,两个Number对象,打印 two one
 * 5.修改getOne为静态同步方法,打印 two one
 * 6.修改两个方法均为静态同步方法,一个Number对象,打印 one two
 * 7.一个静态同步方法,一个非静态同步方法,两个Number对象,打印 two one
 * 8.两个静态同步方法,两个Number对象,打印 one two 
 *
 */
public class TestThread8Monitor {

    public static void main(String[] args)
    {
        Number number = new Number();
        Number number2 = new Number();

        new Thread(() -> number.getOne()).start();
        new Thread(()->number2.getTwo()).start();
//        new Thread(()->number2.getTwo()).start();
//        new Thread(()->number.getThree()).start();

    }
}
class Number{
    public static synchronized void getOne(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }
    public static synchronized void getTwo(){
        System.out.println("two");
    }

    public synchronized void getThree(){
        System.out.println("three");
    }

}

代码逻辑和执行结构都写在上面了

发生了什么?

关键点

  • 非静态方法的锁 默认为this,即锁住了当前的类对象

  • 静态方法的锁 为对应的Class 实例,即锁住了对应类的对象

  • 某一个时刻内,只能有一个线程持有锁,无论几个方法

由于两个number对象都是由Number的class类的实例对象产生的,所以如果锁住了class类的实例对象,其他任何number对象都无法获取锁;

如果锁住了this,即number锁住了number对象,number2锁住了number2对象,那么就互不影响了;

同理锁住this和锁住class类的实例对象也互不影响

原创文章 40 获赞 16 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43925277/article/details/105178684