java 多线程 ReentrantLock互斥锁

 

互斥锁:

在上节中我们谈到了Object类的notify()方法随机唤醒单个线程,而不是唤醒指定线程,这就会导致一个问题,比如三个线程A,B,C,A在执行线程体,B,C在等待,A执行完该B执行了,notify方法随机唤醒一个线程,显然不能用,notifyAll方法把两个线程都唤醒,然后C再次设置成等待,这不太好.

为了解决不能唤醒指定线程的问题,jdk5.0的增加了ReenTrantLock类和Condition接口替换synchronized关键字和wait、notify方法。

先看ReenTrantLock类,暂时不深入分析

ReenTrantLock类:在java.util.concurrent.locks包下面,java.util.concurrent包中是常用的并发控制类

构造方法:

public ReentrantLock(),创建非公平锁对象,随机竞争来得到锁,先lock的线程不一定先获得锁,默认的构造方法。

public ReentrantLock(boolean fair)  ,创建公平锁对象,按线程加锁的顺序来获取锁

构造方法的源码如下(jdk11):

public ReentrantLock() {
        sync = new NonfairSync();
    }

public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
   }
//NonfairSync和NonfairSyn两个类是ReenTrantLock的内部类

列举了几个常用方法:

 void lock()如果锁可以, 对线程上锁., 如果锁已被其他线程占有, 暂时禁用当前线程, 直到当前线程获取到锁,再对线程上锁.

unvoid unlock()对线程解锁,持有锁的线程才能释放锁

boolean tryLock(): 此方法是尝试获取锁,如果锁可用, 则对该线程上锁返回true, 否则返回false. 锁被其他线程占有时, 不会禁用当前线程, 当前线程继续往下执行代码.

Condition newCondition()返回一个Condition实例

getHoldCount() 查询当前线程保持住此锁的次数,当前线程执行(lock和unlock)的次数

getQueueLength()返回正等待获取此锁的线程预估计最大数,比如启动10个线程,1个线程获得锁,此时返回的是9

hasQueuedThread(Thread thread)返回给定的线程是否在等待获取此锁

hasQueuedThreads()是否有线程等待此锁

isFair()判断该锁是否为公平锁

isLock()此锁是否被别的线程获取到

 

Condition接口:在java.util.concurrent.locks包下

Condition是监视器接口,Condition对象是由lock对象创建,同一个锁Lock对象可创建多个Condition的对象,即创建多个对象监视器,每个线程一个监视器。await方法和signal方法用来让指定线程等待和唤醒指定线程.跟wait/notify相同的是,await/signal也是在同步代码区内执行.

常用方法:

void await() throws InterruptedException让指定线程等待

void signal()唤醒指定的正在等待的线程

void signalAll()唤醒所有正在等待的线程

示例:两个线程轮流打印0-100

package chen_chapter_9;

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

public class ReenTrantLockTest01 {
	static PrintNum pn = null;// 内部类调用静态成员变量

	public static void main(String[] args) {
		pn = new PrintNum();
		Thread t1 = new Thread("线程t1") {
			@Override
			public void run() {
				pn.print1();
			}
		};
		Thread t2 = new Thread("线程t2") {
			@Override
			public void run() {
				pn.print2();
			}
		};
		t1.start();
		t2.start();
	}

}

class PrintNum {
	private ReentrantLock r1 = new ReentrantLock();//创建互斥锁对象
	private Condition c1 = r1.newCondition();//创建多个线程的监视器对象
	private Condition c2 = r1.newCondition();
	private int i = 0;
	private boolean flag = true;

	public void print1() {
		while (i < 100) {
			r1.lock();//lock()和unlock()之间的内容类似于以前的synchronized同步代码块
			if (!flag) {
				flag = !flag;
				try {
					c1.await();//指定这个线程等待
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else {
				flag = !flag;
				System.out.println(Thread.currentThread().getName() + " : " + i++);
				c2.signal();//唤醒另一个线程
			}
			r1.unlock();
		}
	}

	public void print2() {
		while (i < 100) {
			r1.lock();
			if (!flag) {
				flag = !flag;
				try {
					c2.await();//指定这个线程等待
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else {
				flag = !flag;
				System.out.println(Thread.currentThread().getName() + " : " + i++);
				c1.signal();//唤醒另一个线程
			}
			r1.unlock();

		}

	}

}

示例:三个线程轮流打印0-100

package chen_chapter_9;

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

public class ReenTrantLockTest2 {
	static PrintNum1 pn = null;// 内部类调用静态成员变量

	public static void main(String[] args) {
		pn = new PrintNum1();
		Thread t1 = new Thread("线程t1") {
			@Override
			public void run() {
				pn.print1();
			}
		};
		Thread t2 = new Thread("线程t2") {
			@Override
			public void run() {
				pn.print2();
			}
		};
		Thread t3 = new Thread("线程t3") {
			@Override
			public void run() {
				pn.print3();
			}
		};
		t1.start();
		t2.start();
		t3.start();
	}

}

class PrintNum1 {
	private ReentrantLock r1 = new ReentrantLock();// 创建互斥锁对象
	private Condition c1 = r1.newCondition();// 创建多个线程的监视器对象
	private Condition c2 = r1.newCondition();
	private Condition c3 = r1.newCondition();
	private int i = 0;
	private int flag = 1;

	public void print1() {
		while (i < 100) {
			r1.lock();// lock()和unlock()之间的内容类似于以前的synchronized同步代码块
			if (flag != 1) { // 三个线程中,保证对同一个变量,只有一个不进入等待状态
				try {
					c1.await();// 指定这个线程等待
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else {
				System.out.println(Thread.currentThread().getName() + " : " + i++);
				flag = 2;
				c2.signal();// 唤醒另一个线程
			}
			r1.unlock();
		}
	}

	public void print2() {
		while (i < 100) {
			r1.lock();
			if (flag != 2) {
				try {
					c2.await();// 指定这个线程等待
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else {

				System.out.println(Thread.currentThread().getName() + " : " + i++);
				flag = 3;
				c3.signal();// 唤醒另一个线程
			}
			r1.unlock();

		}

	}

	public void print3() {
		while (i < 100) {
			r1.lock();
			if (flag != 3) {
				try {
					c3.await();// 指定这个线程等待
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else {

				System.out.println(Thread.currentThread().getName() + " : " + i++);
				flag = 1;
				c1.signal();// 唤醒另一个线程
			}
			r1.unlock();

		}

	}

}

 

synchronized和ReenTrantLock的区别:

synchronized

 

ReenTrantLock

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,互斥锁是一种用于并发控制的机制,用于保证多个线程之间的互斥操作。在Java中,有几种常见的互斥锁实现方式。 一种常见的实现方式是使用synchronized关键字。通过在代码块或方法前使用synchronized关键字,可以实现对临界区域的互斥访问。具体来说,当一个线程访问某个对象的synchronized代码块或方法时,其他试图访问该对象的线程将会被阻塞,直到当前线程执行完这个代码块或方法并释放锁。 另一种常见的实现方式是使用ReentrantLock互斥锁。ReentrantLockJava.util.concurrent包中提供的一种互斥锁实现。与synchronized关键字相比,ReentrantLock提供了更多的灵活性和功能,例如可重入性、公平性和可中断性等。通过在代码块中使用ReentrantLocklock()和unlock()方法,可以实现对临界区域的互斥访问。 总的来说,互斥锁Java多线程编程中起着重要的作用,可以保证线程之间的互斥操作,避免数据竞争和不一致的问题。在选择互斥锁实现方式时,可以根据具体需求和场景选择使用synchronized关键字或ReentrantLock互斥锁。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Java中的互斥锁介绍](https://blog.csdn.net/java_cpp_/article/details/130477343)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [Java多线程 ReentrantLock互斥锁详解](https://download.csdn.net/download/weixin_38688956/12746813)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值