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

来源:互联网 发布:淘宝发安能物流好恶心 编辑:程序博客网 时间:2024/05/01 13:09

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

 

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

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() {@Overridepublic void run() {bankOperator.addAccounts();}}).start();new Thread(new Runnable() {@Overridepublic 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() {@Overridepublic void run() {bankOperator.addAccounts();}}).start();new Thread(new Runnable() {@Overridepublic 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);}}}}

执行结果:

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

 

有关synchronizedLock的比较可以参看:

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


0 0
原创粉丝点击