线程Thread(JAVA) 篇八 线程间通信(Lock Condition)

本文探讨Java中线程间通信的高级机制,重点介绍Lock和Condition接口如何改进传统synchronized方法,实现更灵活、高效的线程同步,通过实例展示输入输出线程的正确交互及按序交替执行。

线程Thread(JAVA) 篇七 线程间通信(wait(),notify(),notifyAll())–等待唤醒机制
其实在JAVA1.5以后关于同步和锁做了封装。如图所示
同步和锁对应图
通过查看API java.util.concurrent.locks包中的Lock接口可以知道:
Lock实现提供比使用synchronized方法和语句可以获得的更广泛的锁定操作。 它们允许更灵活的结构化,可能具有完全不同的属性,并且可以支持多个相关联的对象Condition。
并且查看到了Lock的惯用方式:

	 Lock l = ...;
     l.lock();
     try {
         // access the resource protected by this lock
     } finally {
         l.unlock();
     }

通过查看Condition接口文档,可以知道此接口替代了Object中的wait(),notify(),notyfyAll()方法,将这些监视器方法进行封装,变成了Condition监视器对象,可以和任意锁进行组合。会看到Condition惯用方式:

class BoundedBuffer {
   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(); }
   }
 } 

因此我们修改线程Thread(JAVA) 篇七 线程间通信(wait(),notify(),notifyAll())–等待唤醒机制中的代码为:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 煤炭类[同一资源]
 */
class Coal
{
	private String  carName;
	private String weight;
	boolean flag = true;
	//创建锁对象
	Lock lock = new ReentrantLock();
	//通过锁对象创建Condition对象
	Condition inputCondition = lock.newCondition();
	Condition outputCondition = lock.newCondition();
	public void input(String carName, String weight) 
	{
		
		lock.lock();//获取锁
		try
		{
			//当标志位为 true时,输入煤炭
			if(flag) 
			{
				this.carName = carName;
				this.weight = weight;
				System.out.println(carName +" ... "+weight);
				flag = false;//标志位置false
				outputCondition.signal();//唤醒输出线程中的一个
			}
			else 
			{//当标志位为 false时,输出煤炭,输入线程进入等待状态
				try
				{
					inputCondition.await();//输入线程等待
				} catch (InterruptedException e)
				{
					e.printStackTrace();
				}
			}	
		} finally
		{
			lock.unlock();//释放锁
		}
		
		
	}
	public synchronized void output(String carName, String weight) 
	{
		lock.lock();//获取锁
		try
		{
			//当标志位为 false时,输出煤炭
			if(!flag) 
			{
				this.carName = carName;
				this.weight = weight;
				System.out.println(carName +" ... "+weight);
				flag = true;//标志位置为true
				inputCondition.signal();//唤醒输入线程中的一个线程
			}
			else
			{//当标志位为 true时,输入煤炭,输出线程进入等待状态
				try
				{
					outputCondition.await();//输出线程等待
				} catch (InterruptedException e1)
				{
					e1.printStackTrace();
				}
			}
		} finally
		{
			lock.unlock();//释放锁
		}
		
	}
	
}
/**
 * 往里输送煤炭类
 */
class InputCar implements Runnable
{
	Coal coal;
	public InputCar(Coal coal)
	{
		this.coal = coal;
	}
	@Override
	public void run()
	{
		while(true)
		{
			coal.input("输入车", "输入10吨");
		}
	
	}
}

/**
 * 往外输送煤炭类
 */
class OutputCar implements Runnable
{
	Coal coal;
	public OutputCar(Coal coal)
	{
		this.coal = coal;
	}
	@Override
	public void run()
	{
		while(true) 
		{
			coal.output( "车次-输出车", "碳重-输出车5吨吨");
		}
	}
}
/**
 * 测试
 */
public class Test
{
	public static void main(String[] args)
	{
		
		Coal coal = new Coal();
		
		InputCar inputCar = new InputCar(coal);
		OutputCar outputCar = new OutputCar(coal);
		
		Thread thread = new Thread(inputCar);
		Thread thread2 = new Thread(inputCar);
		
		Thread thread3 = new Thread(outputCar);
		Thread thread4 = new Thread(outputCar);
		
		thread.start();
		thread2.start();
		thread3.start();
		thread4.start();
	}
}

打印结果为:

输入车 … 输入10吨
车次-输出车 … 碳重-输出车5吨吨
输入车 … 输入10吨
车次-输出车 … 碳重-输出车5吨吨
输入车 … 输入10吨
车次-输出车 … 碳重-输出车5吨吨
输入车 … 输入10吨
车次-输出车 … 碳重-输出车5吨吨
输入车 … 输入10吨
车次-输出车 … 碳重-输出车5吨吨
……
经过修改的代码弥补了notifyAll()方法的缺陷(把自己同一方的线程也唤醒了。这样会降低运行效率等)。
通过给一个锁上面加上多组监视器,用于解决notifyAll()的问题。
如下是一道面试器,关于Lock Condition的应用:

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

/*
 * 编写一个程序,开启三个线程。这三个线程的ID分别为A,B,C,每个线程将自己的ID在屏幕上打印10遍。
 * 要求输出的结果必须按照顺序显示 如:ABCABCABC……依次递归
 */
public class TestABCAlternate
{
	public static void main(String[] args)
	{
		AlternateDemo alternateDemo = new AlternateDemo();
		
			new Thread(new Runnable()
			{
				@Override
				public void run()
				{
					for (int i = 1; i <= 10; i++)
					{
						alternateDemo.loopA(i);
					}
				}
			},"A").start();
		
			new Thread(new Runnable()
			{
				@Override
				public void run()
				{
					for (int i = 1; i <= 10; i++)
					{
						alternateDemo.loopB(i);
					}
				}
			},"B").start();
			
			new Thread(new Runnable()
			{
				@Override
				public void run()
				{
					for (int i = 1; i <= 10; i++)
					{
						alternateDemo.loopC(i);
						System.out.println("-----------------------------------");
					}	
				}
			},"C").start();
		
	}
}
class AlternateDemo
{
	//设置标志位
	int flag = 1;
	Lock lock = new ReentrantLock();
	Condition conditionA = lock.newCondition();
	Condition conditionB = lock.newCondition();
	Condition conditionC = lock.newCondition();
	public void loopA(int numOfTime)
	{
		lock.lock();//获取锁
		try
		{
			if(flag != 1) 
			{
				try
				{
					conditionA.await();//线程A等待
				} catch (InterruptedException e)
				{
					e.printStackTrace();
				}
			}
			System.out.println(Thread.currentThread().getName()+" : "+ numOfTime);
			flag = 2;//标志位置2
			conditionB.signal();//唤醒线程B	
		} finally
		{
			lock.unlock();//释放锁
		}
	}
	
	public void loopB(int numOfTime)
	{
		lock.lock();//获取锁
		try
		{
			if(flag != 2) 
			{
				try
				{
					conditionB.await();//线程A等待
				} catch (InterruptedException e)
				{
					e.printStackTrace();
				}	
			}
			System.out.println(Thread.currentThread().getName()+" : "+ numOfTime);
			flag = 3;//标志位置3
			conditionC.signal();//唤醒线程C		
		} finally
		{
			lock.unlock();//释放锁
		}
	}
	
	public void loopC(int numOfTime) 
	{
		lock.lock();//获取锁
		try
		{
			if(flag != 3) 
			{
				try
				{
					conditionC.await();//线程A等待
				} catch (InterruptedException e)
				{
					e.printStackTrace();
				}	
			}
			System.out.println(Thread.currentThread().getName()+" : "+ numOfTime);
			flag = 1;//标志位置1
			conditionA.signal();//唤醒线程A	
		} finally
		{
			lock.unlock();//释放锁
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值