Java多线程学习笔记4——lock锁Condition

Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,使用其 newCondition() 方法。

Condition 将 Object 监视器方法(waitnotify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。

下面使用condition的await和singal方法可以替代object的wait和notify方法,lock锁替代了synchronized方法块,实例代码如下:

      public void init() {
		Business business = new Business();
		// 子线程
		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 50; i++) {business.sub(i);}
			}
		}).start();

		// 主线程
		for (int j = 0; j < 50; j++) {business.main(j);}
	}
	class Business {
		boolean isSub = true;
		public void main(int n) {
			Lock lock = new ReentrantLock();
			Condition condition = lock.newCondition();
			lock.lock();
			try {
				if (isSub) {condition.await();}

				for (int i = 0; i < 7; i++) {
					System.out.println("main ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次");
				}
				System.out.println();
				isSub = true;
				condition.signal();
			} catch (Exception e) {
				lock.unlock();
			}
		}
		public void sub(int n) {
			Lock lock = new ReentrantLock();
			Condition condition = lock.newCondition();
			lock.lock();
			try {
				if (!isSub) {condition.await();}
				for (int i = 0; i < 13; i++) {
					System.out.println("sub ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次");
				}
				System.out.println();
				isSub = false;
				condition.signal();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}
	}

condition不仅可以替代object的wait和notify方法,可以实现多路复用的功能,废话少说先上代码:

	final Lock lock = new ReentrantLock();
	final Condition notFull = lock.newCondition();
	final Condition notEmpty = lock.newCondition();

	final Object[] items = new Object[100];
	int putptr, takeptr, count;

	public void put(Object x) throws InterruptedException {
		lock.lock();
		try {
			while (count == items.length)
				notFull.await();
			items[putptr] = x;
			if (++putptr == items.length)
				putptr = 0;
			++count;
			notEmpty.signal();
		} finally {
			lock.unlock();
		}
	}

	public Object take() throws InterruptedException {
		lock.lock();
		try {
			while (count == 0)
				notEmpty.await();
			Object x = items[takeptr];
			if (++takeptr == items.length)
				takeptr = 0;
			--count;
			notFull.signal();
			return x;
		} finally {
			lock.unlock();
		}
	}

作为一个示例,假定有一个绑定的缓冲区,它支持 put 和 take 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待 set 中保存 put 线程和 take 线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition 实例来做到这一点。

注意,Condition 实例只是一些普通的对象,它们自身可以用作 synchronized 语句中的目标,并且可以调用自己的 wait 和 notification 监视器方法。获取 Condition 实例的监视器锁或者使用其监视器方法,与获取和该 Condition 相关的 Lock 或使用其 waiting 和 signalling 方法没有什么特定的关系。为了避免混淆,建议除了在其自身的实现中之外,切勿以这种方式使用 Condition 实例。

除非另行说明,否则为任何参数传递 null 值将导致抛出 NullPointerException

此外,提供一个第一个实例代码的升级,让三个线程有序的各执行20次。

	public void init() {
		Business business = new Business();
		// 子线程
		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 20; i++) {business.sub(i);}
			}
		}).start();
		
		// 次子线程
		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 20; i++) {business.subSub(i);}
			}
		}).start();
		

		// 主线程
		for (int j = 0; j < 20; j++) {business.main(j);}
	}

	class Business {

		int flag=0;
		Lock lock = new ReentrantLock();
		Condition condition0 = lock.newCondition();
		Condition condition1 = lock.newCondition();
		Condition condition2 = lock.newCondition();
		public void main(int n) {
			lock.lock();
			try {
				if (flag!=0) {condition0.await();}
				for (int i = 0; i < 7; i++) {
					System.out.println("main ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次");
				}
				System.out.println();
				flag=1;
				condition1.signal();
			} catch (Exception e) {
				lock.unlock();
			}

		}

		public void sub(int n) {
		
			lock.lock();
			try {
				if (flag!=1) {condition1.await();}//
				for (int i = 0; i < 13; i++) {
					System.out.println("sub ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次");
				}
				System.out.println();
				flag = 2;
				condition2.signal();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}
		
		
		public void subSub(int n) {
		
			lock.lock();
			try {
				if (flag!=2) {condition2.await();}//
				for (int i = 0; i < 23; i++) {
					System.out.println("sub--Sub ----" + Thread.currentThread().getName() + ",第" + n + "次运行,当前循环了" + i + "次");
				}
				System.out.println();
				flag = 0;
				condition0.signal();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}
	}

	public static void main(String[] args) {
		new ThreeLockContidion2().init();
	}


猜你喜欢

转载自blog.csdn.net/zhangkang65/article/details/79420703