多线程系列二——java线程间的互斥与同步

       “线程互斥是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。”

 

我们可以用银行转账的例子加以说明:

1、甲乙两用户对银行同一账户进行操作,余额为1000元;

2、甲用户将银行余额1000元读取到本地,进行取款操作。在进行取款过程中,乙用户向银行账户进行存款300元操作并将账户余额更新,而此时甲用户进行取款是建立在原始1000元的基础上进行的。完成操作后将最终错误的800元余额更新至银行账户。。。

 

用程序模拟此示例:

public class TestTransferAccounts {
	
	//存取银行账户余额
	static int balance = 1000;
	
	//main方法中模拟两个用户同时对该银行账户进行更新(其中一个进行取款操作,另一个对账户进行汇款操作)
	public static void main(String[] args) {
		
		new TestTransferAccounts().test();
	}
	
	
	public void test(){
		BankOperator bankOperator= new BankOperator();
		
		new Thread(
			new Runnable() {
				
				@Override
				public void run() {
					bankOperator.addAccounts();					
				}
			}
		).start();
		
		new Thread(
				new Runnable() {
					
					@Override
					public void run() {
						bankOperator.reduceAccounts();					
					}
				}
			).start();
		
		//主线程等到另外两个线程操作完成后,查询账户余额进行打印。
		try {
			Thread.sleep(1000);
			System.out.println("查询账户余额:" + balance);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	class BankOperator{
		//汇款操作方法
		public void addAccounts(){
			//将余额读取到本地
			int myBalance = balance;
			//中间处理过程花费500ms。。。
			try {
				Thread.sleep(200);
				myBalance += 300;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			//将余额更新回账目
			balance = myBalance;
			System.out.println(Thread.currentThread().getName() + ":" + balance);
		}

		//取款操作方法
		public void reduceAccounts(){
			//将余额读取到本地
			int myBalance = balance;
			//中间处理过程花费200ms。。。
			try {
				Thread.sleep(500);
				myBalance -= 200;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			//将余额更新回账目
			balance = myBalance;
			System.out.println(Thread.currentThread().getName() + ":" + balance);
		}
	}
}

执行结果:

 

正如文章开头我们提到的线程互斥概念,我们需要对汇款、取款两个线程添加互斥机制,同时只能允许一个用户调用addAccountsreduceAccounts方法,我们需要对BankOperator对象内的这两个方法添加同步的机制,防止银行将我们的账户余额搞乱。

public class TestTransferAccounts {
	
	//存取银行账户余额
	static int balance = 1000;
	
	//main方法中模拟两个用户同时对该银行账户进行更新(其中一个进行取款操作,另一个对账户进行汇款操作)
	public static void main(String[] args) {
		
		new TestTransferAccounts().test();
	}
	
	
	public void test(){
		BankOperator bankOperator= new BankOperator();
		
		new Thread(
			new Runnable() {
				
				@Override
				public void run() {
					bankOperator.addAccounts();					
				}
			}
		).start();
		
		new Thread(
				new Runnable() {
					
					@Override
					public void run() {
						bankOperator.reduceAccounts();					
					}
				}
			).start();
		
		//主线程等到另外两个线程操作完成后,查询账户余额进行打印。
		try {
			Thread.sleep(1000);
			System.out.println("查询账户余额:" + balance);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	class BankOperator{
		//亏款操作方法
		public void addAccounts(){
			synchronized (this) {
				//将余额读取到本地
				int myBalance = balance;
				//中间处理过程花费500ms。。。
				try {
					Thread.sleep(500);
					myBalance += 300;
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//将余额更新回账目
				balance = myBalance;
				System.out.println(Thread.currentThread().getName() + ":" + balance);
								
			}
		}

		//取款操作方法
		public void reduceAccounts(){
			synchronized (this) {
				//将余额读取到本地
				int myBalance = balance;
				//中间处理过程花费200ms。。。
				try {
					Thread.sleep(500);
					myBalance -= 200;
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//将余额更新回账目
				balance = myBalance;
				System.out.println(Thread.currentThread().getName() + ":" + balance);
			}
		}
	}
}

执行结果:

多线程系列二——java线程间的互斥与同步_第1张图片

synchronized关键字已经帮我们实现了同步的效果,而jdk5.0为我们提供了Lock对象,来实现更为强大的同步效果。

 

有关synchronizedLock的比较可以参看:

http://www.cnblogs.com/benshan/p/3551987.html#top


你可能感兴趣的:(多线程系列二——java线程间的互斥与同步)