您的位置 首页 java

JAVA多线程-读写锁

JAVA 读写锁:前面讲到了可重入锁,虽然使用方面会比synchronized性能高,但是还是没有达到我们理想得要求,我们实际项目中,比如同时访问写的时候需要互斥,或者写的时候也读也需要等待,但是多个线程同时读得时候,不需要等待,这时候就要用到读写锁了ReadWriteLock,我们先看下ReadWriteLock接口:

 public interface ReadWrite lock  {
 
    /**
     * 返回一个读锁
     */ 
    Lock readLock();
 
    /**
     * 返回一个写锁
     */ 
    Lock writeLock();
}  

我们看下读写锁得用法,首先同时进行写,我们看下账户类:

 package com.ck.thread;
 
import java.math. BigDecimal ;
 
import java.util.concurrent.locks.ReadWriteLock;
 
import java.util.concurrent.locks.ReentrantReadWriteLock;
 
public class  account  {
 
    private ReadWriteLock lock = new ReentrantReadWriteLock();
 
    private BigDecimal balnace = new BigDecimal("100");
 
    //充值
 
    public void add(BigDecimal amount ) throws InterruptedException {
 
        //写锁
 
        lock.writeLock().lock();
 
        System.out.println(" 开始充值,线程名: " + Thread.currentThread().getName());
 
        try {
 
            Thread.sleep(2000);
 
            balnace = balnace.add(amount);
 
            System.out.println(" 结束充值,线程名: " + Thread.currentThread().getName());
 
        } catch (InterruptedException e) {
 
            e.printStackTrace();
 
        }finally {
 
            lock.writeLock().unlock();
 
        }
 
    }
 
 
    //查询余额
 
    public void getBalace() {
 
        //读锁
 
        lock.readLock().lock();
 
        try {
 
            System.out.println("开始查询线程名: " + Thread.currentThread().getName() );
 
            try {
 
                Thread.sleep(2000);
 
            } catch (InterruptedException e) {
 
                e.printStackTrace();
 
            }
 
            System.out.println("查询结果线程名: " + Thread.currentThread().getName() +", 余额:" + balnace);
 
        }finally {
 
            lock.readLock().unlock();
 
        }
 
    }  
 
}  

然后充值类:

 package com.ck.thread;
 
import java.math.BigDecimal;
 
public class CzThread extends Thread{
 
    private Account account;
 
    public CzThread(Account account) {
 
        this.account = account;
 
    }
 
 
    @ Override 
 
    public void run() {
 
        try {
 
            account.add(new BigDecimal("100"));
 
        } catch (InterruptedException e) {
 
            e.printStackTrace();
 
        }
 
    }
 
    public Account getAccount() {
 
        return account;
 
    }
 
    public void setAccount(Account account) {
 
        this.account = account;
 
    }
 
}  

获取余额线程:

 package com.ck.thread;
 
public class GetBalaceThread extends Thread{
 
    private Account account;
 
    public GetBalaceThread(Account account) {
 
        super();
 
        this.account = account;
 
    }
 
 
    @Override
 
    public void run() {
 
        account.getBalace();
 
    }
 
  
    public Account getAccount() {
 
        return account;
 
    }
 
    public void setAccount(Account account) {
 
        this.account = account;
 
    }
 
}  

主线程方法:

 package com.ck.thread;
 
 
 
 
 
public class MainThread {
 
    public static void main(String[] args) throws InterruptedException {
 
        Account account = new Account();
 
       
 
        CzThread cz1 = new CzThread(account);
 
        cz1.setName("thread1");
 
        cz1.start();
 
       
 
        CzThread cz2 = new CzThread(account);
 
        cz2.setName("thread2");
 
        cz2.start();
 
    }
 
}  

执行结果:

 开始充值,线程名: thread2
 
 结束充值,线程名: thread2
 
 开始充值,线程名: thread1
 
 结束充值,线程名: thread1  

我们通过结果可以看到,因为充值得线程都调用了Account的add方法,该方法上加了写的锁,所以都需要等待,我们看到线程2执行完了才执行线程1,说明写锁是互斥的,我们继续看些读写的情况,修改主线程如下:

 public class MainThread {
 
 
    public static void main(String[] args) throws InterruptedException {
 
        Account account = new Account();
 
       
        CzThread cz1 = new CzThread(account);
 
        cz1.setName("thread1");
 
        cz1.start();
       
 
        GetBalaceThread cz2 = new GetBalaceThread(account);
 
        cz2.setName("thread2");
 
        cz2.start();
 
    }
 
}  

执行结果:

 开始充值,线程名: thread1
 
 结束充值,线程名: thread1
 
开始查询线程名: thread2
 
查询结果线程名: thread2, 余额:200  

通过结果我们可以看到,先执行充值的情况下,获取余额线程需要等待,说明读写锁也是相互互斥的,下面我们继续看下读读锁,修改主线程如下:

 public class MainThread {
 
 
    public static void main(String[] args) throws InterruptedException {
 
        Account account = new Account();
 
        GetBalaceThread cz1 = new GetBalaceThread(account);
 
        cz1.setName("thread1");
 
        cz1.start();
 
      
        GetBalaceThread cz2 = new GetBalaceThread(account);
 
        cz2.setName("thread2");
 
        cz2.start();
 
    }
 
}  

执行结果:

 开始查询线程名: thread1
 
开始查询线程名: thread2
 
查询结果线程名: thread1, 余额:100
 
查询结果线程名: thread2, 余额:100  

通过结果可以看到,读锁直接不存在竞争锁的关系,可以同时访问一个方法。

总结:读写锁可以提供程序并发的性能,而且比较灵活,具体原理我们后续会继续介绍。

文章来源:智云一二三科技

文章标题:JAVA多线程-读写锁

文章地址:https://www.zhihuclub.com/184478.shtml

关于作者: 智云科技

热门文章

网站地图