Java多线程之Condition的使用及源码解析

java中条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是通过一个Lock对象上调用newCondition()方法来获取的,这样,条件就和一个锁对象绑定起来了。因此,Java中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全。

 

条件变量的出现是为了更精细控制线程等待与唤醒,在Java5之前,线程的等待与唤醒依靠的是Object对象的wait()和notify()/notifyAll()方法,这样的处理不够精细,如不能精确指定唤醒哪个线程。

通熟易懂的说,就是消费者/生产者的场景中,在原来的基础上,增加了队列满时及时通知消费者,队列空时及时通知生产者的优化,通常是两个条件变量一起出现,一个控制值,但两个条件变量可以毫无关系,终归来说还是在Lock的范围内。所以,从本质上来说,是对Object监视器的场景性优化,而不是全新机制的引入。

而在Java5中,一个锁可以有多个条件,每个条件上可以有多个线程等待,通过调用await()方法,可以让线程在该条件下等待。当调用signalAll()方法,又可以唤醒该条件下的等待的线程。

 

案例:定义三个任务类A、B、C分别含有方法a()、b()、c()并分别循环打印结果"a"、"b"、"c",启动三个线程分别执行A、B、C类中的a()、b()、c()并打印出结果。

a
b
c
a
b
c
a
b
c
a
b
c

......

使用传统的wait()、notify()方法,接合synchronized关键字实现                       缺点:不能指定唤醒哪个线程,

package cn.itcats.thread.Condition1;

import cn.itcats.thread.Condition1.Condition1.B.C;

//顺序打印abcabc————使用线程之间的通信技术
public class Condition1 {
	private int signal = 0;
	
	public synchronized void a() {
		while(signal != 0) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("a");
		signal++;
		notifyAll();
	}

	public synchronized void b() {
		while(signal != 1) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("b");
		signal++;
		notifyAll();
	}

	public synchronized void c() {
		while(signal != 2) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("c");
		signal = 0;
		notifyAll();
	}
	
	public static void main(String[] args) {
		Condition1 condition1 = new Condition1();
		A a = new A(condition1);
		B b = new B(condition1);
		C c = new C(condition1);
		new Thread(a).start();
		new Thread(b).start();
		new Thread(c).start();
	}

	 static class A implements Runnable {
		private Condition1 condition1;

		public A(Condition1 condition1) {
			this.condition1 = condition1;
		}

		public void run() {
			while (true) {
				condition1.a();
				try {
					Thread.sleep(800);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

	}

	 static class B implements Runnable {
		private Condition1 condition1;

		public B(Condition1 condition1) {
			this.condition1 = condition1;
		}

		public void run() {
			while (true) {
				condition1.b();
				try {
					Thread.sleep(800);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

		static class C implements Runnable {
			private Condition1 condition1;

			public C(Condition1 condition1) {
				this.condition1 = condition1;
			}

			public void run() {
				while (true) {
					condition1.c();
					try {
						Thread.sleep(800);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
		
	}
}

 

使用Condition接口中await()和signal()实现,接合Lock接口

1、把synchronized该换成Lock接口的lock()和unlock()实现

2、控制3个方法的条件,则创建3个Condition接口对象

3、把wait()方法改换成await(),把notify()方法该换成   被唤醒的Condition对象.signal()

package cn.itcats.thread.Condition2;

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

import cn.itcats.thread.Condition2.Condition1.B.C;

//顺序打印abcabc————使用线程之间的通信技术
public class Condition1 {
	private int signal = 0;
	Lock lock = new ReentrantLock();
	Condition a = lock.newCondition();
	Condition b = lock.newCondition();
	Condition c = lock.newCondition();
	
	//删除synchronized关键字,改用Lock
	public void a() {
		lock.lock();
		while(signal != 0) {
			try {
				a.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("a");
		signal++;
		//唤醒b
		b.signal();
		lock.unlock();
	}

	public  void b() {
		lock.lock();
		while(signal != 1) {
			try {
				b.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("b");
		signal++;
		c.signal();
		lock.unlock();
	}

	public void c() {
		lock.lock();
		while(signal != 2) {
			try {
				c.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("c");
		signal = 0;
		a.signal();
		lock.unlock();
	}
	
	public static void main(String[] args) {
		Condition1 condition1 = new Condition1();
		A a = new A(condition1);
		B b = new B(condition1);
		C c = new C(condition1);
		new Thread(a).start();
		new Thread(b).start();
		new Thread(c).start();
	}

	 static class A implements Runnable {
		private Condition1 condition1;

		public A(Condition1 condition1) {
			this.condition1 = condition1;
		}

		public void run() {
			while (true) {
				condition1.a();
				try {
					Thread.sleep(800);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

	}

	 static class B implements Runnable {
		private Condition1 condition1;

		public B(Condition1 condition1) {
			this.condition1 = condition1;
		}

		public void run() {
			while (true) {
				condition1.b();
				try {
					Thread.sleep(800);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

		static class C implements Runnable {
			private Condition1 condition1;

			public C(Condition1 condition1) {
				this.condition1 = condition1;
			}

			public void run() {
				while (true) {
					condition1.c();
					try {
						Thread.sleep(800);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
		
	}
}

 

如何获取Condition对象和Condition接口的实现类

//如何获取Condition对象,ReentrantLock源码中newCondition()方法
 public Condition newCondition() {
        return sync.newCondition();
    }



//顺着源码找到Sync类中的newCondition()方法
 final ConditionObject newCondition() {
            //说明了Condition接口的有且只有一个实现类就是ConditionObject
            return new ConditionObject();
        }






//而ConditionObject又是AQS类中的一个内部类
//空参构造         public ConditionObject() { }
//关注ConditionObject中的await()和signal()方法





//ConditionObject中的 await()方法
public final void await() throws InterruptedException {

            //1、若线程中断则抛出线程中断异常,则无需等待await()
            if (Thread.interrupted())
                throw new InterruptedException();

            //2、添加到等待队列,如果lastWaiter是cancel状态,那么会把它踢出Condition队列
            Node node = addConditionWaiter();
            //3、调用tryRelease,释放线程所获取的lock
            int savedState = fullyRelease(node);
            int interruptMode = 0;
            //4、判断node是否在同步器的队列中
            while (!isOnSyncQueue(node)) {
                //若不在同步队列,park()和unpark()方法实现阻塞线程和解除线程阻塞
                LockSupport.park(this);
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }

            //自旋等待尝试再次获取锁,调用acquireQueued方法
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
            if (node.nextWaiter != null) // clean up if cancelled
                unlinkCancelledWaiters();
            if (interruptMode != 0)
                reportInterruptAfterWait(interruptMode);
        }



//signal()源码解析
public final void signal() {
            //判断是否为独占锁
            if (!isHeldExclusively())
                //如果不是独占锁则抛出异常
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            //第一个节点不为空
            if (first != null)
                doSignal(first);
        }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值