ReentrantLock synchronized的区别以及简单示范

ReentrantLock简称可重入的互斥锁,当一个线程多次获取它所占有的锁资源时,是可以成功的,每当成功获取一次的时候,其保持计数将会+1,并且在其执行完毕释放锁的时候,保持计数随之清零;至于互斥的概念,就是当一个线程持有该锁时,其他需要获取该锁的线程将一直等待直至该锁被释放;这是多线程中实现同步的一种方式,它实现了synchronized的基本功能,同时也拓展了一些新的方法。

synchronized和ReentrantLock的区别:
   除了synchronized的功能,多了三个高级功能:等待可中断,公平锁,绑定多个Condition.

1.等待可中断
在持有锁的线程长时间不释放锁的时候,等待的线程可以选择放弃等待.   tryLock(long timeout, TimeUnit unit)
2.公平锁
按照申请锁的顺序来一次获得锁称为公平锁.synchronized的是非公平锁,ReentrantLock可以通过构造函数实现公平锁.    new RenentrantLock(boolean fair)
3.绑定多个Condition
通过多次newCondition可以获得多个Condition对象,可以简单的实现比较复杂的线程同步的功能.通过await(),signal(); 

  • 首先声明一个银行卡的辅助类
package com.test.demo;

public class BankCard {

	private String cardNo;
	
	private int balance;

	public String getCardNo() {
		return cardNo;
	}

	public void setCardNo(String cardNo) {
		this.cardNo = cardNo;
	}

	public int getBalance() {
		return balance;
	}

	public void setBalance(int balance) {
		this.balance = balance;
	}
	
}
  • 创建Husband类执行存钱操作
package com.test.demo;

import java.util.concurrent.locks.Lock;

public class Husband implements Runnable{

	private BankCard card;
	
	private Lock lock;
	
	public Husband(BankCard card, Lock lock){
		this.card = card;
		this.lock = lock;
	}

	public void run() {
		while(true){
			lock.lock();
			System.out.println("丈夫准备存钱,账户余额为: "+ card.getBalance());
			card.setBalance(card.getBalance() + 500);
			System.out.println("丈夫存钱完毕,账户余额为: " + card.getBalance());
			lock.unlock();
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
  • 创建Wife类执行消费操作
package com.test.demo;

import java.util.concurrent.locks.Lock;

public class Wife implements Runnable{

	private BankCard card;
	
	private Lock lock;
	
	public Wife(BankCard card, Lock lock){
		this.card = card;
		this.lock = lock;
	}

	public void run() {
		while(true){
			lock.lock();
			System.out.println("妻子要消费,账户余额为: "+ card.getBalance());
			card.setBalance(card.getBalance() - 1000);
			System.out.println("妻子消费完毕,账户余额为:" +card.getBalance());
			lock.unlock();
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	
}
  • 启动线程进行测试
package com.test.demo;

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

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main( String[] args )
    {
       BankCard card = new BankCard();
       card.setBalance(10000);
       Lock lock = new ReentrantLock();
       Wife child = new Wife(card, lock);
       Husband father = new Husband(card, lock);
       new Thread(child).start();
       new Thread(father).start();
    }
    
}

 运行效果如下,我们可以看到正常操作

丈夫准备存钱,账户余额为: 10000
丈夫存钱完毕,账户余额为: 10500
妻子要消费,账户余额为: 10500
妻子消费完毕,账户余额为:9500
妻子要消费,账户余额为: 9500
妻子消费完毕,账户余额为:8500
丈夫准备存钱,账户余额为: 8500
丈夫存钱完毕,账户余额为: 9000
妻子要消费,账户余额为: 9000
妻子消费完毕,账户余额为:8000
丈夫准备存钱,账户余额为: 8000
丈夫存钱完毕,账户余额为: 8500
丈夫准备存钱,账户余额为: 8500
丈夫存钱完毕,账户余额为: 9000
妻子要消费,账户余额为: 9000
妻子消费完毕,账户余额为:8000
  • 当妻子锁定后不释放锁
package com.test.demo;

import java.util.concurrent.locks.Lock;

public class Wife implements Runnable{

	private BankCard card;
	
	private Lock lock;
	
	public Wife(BankCard card, Lock lock){
		this.card = card;
		this.lock = lock;
	}

	public void run() {
		while(true){
			lock.lock();
			System.out.println("妻子要消费,账户余额为: "+ card.getBalance());
			card.setBalance(card.getBalance() - 1000);
			System.out.println("妻子消费完毕,账户余额为:" +card.getBalance());
			//lock.unlock();
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	
}

 运行效果如下:

妻子要消费,账户余额为: 10000
妻子消费完毕,账户余额为:9000
妻子要消费,账户余额为: 9000
妻子消费完毕,账户余额为:8000
妻子要消费,账户余额为: 8000
妻子消费完毕,账户余额为:7000
妻子要消费,账户余额为: 7000
妻子消费完毕,账户余额为:6000
妻子要消费,账户余额为: 6000
妻子消费完毕,账户余额为:5000
妻子要消费,账户余额为: 5000
妻子消费完毕,账户余额为:4000
妻子要消费,账户余额为: 4000
妻子消费完毕,账户余额为:3000
妻子要消费,账户余额为: 3000
妻子消费完毕,账户余额为:2000
妻子要消费,账户余额为: 2000
妻子消费完毕,账户余额为:1000

 可以看到获取不到锁的Husband线程将一直处于阻塞状态!

除此之外,ReentrantLock提供了灵活的中断机制,第一种:ReentrantLock尝试获取锁时,可以指定等待的时间,当超过等待时间后则放弃执行并返回一个boolean值;第二种:ReentrantLock提供了可中断锁操作。

try {
            if (lock.tryLock(5, TimeUnit.SECONDS)) {  //如果已经被lock,尝试等待5s,看是否可以获得锁,如果5s后仍然无法获得锁则返回false继续执行
                 try {
                            //操作
                       } finally {
                            lock.unlock();
                       }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace(); //当前线程被中断时(interrupt),会抛InterruptedException                 
                }

以上为本次的简单演示,仅仅供个人的学习所用!

猜你喜欢

转载自newbee-zc.iteye.com/blog/2249470