Java 多线程(五) 多线程的同步
2013-02-16 20:19
204 查看
Java 多线程(五) 多线程的同步
为什么要引入同步机制
在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源。必须对这种潜在资源冲突进行预防。解决方法:在线程使用一个资源时为其加锁即可。
访问资源的第一个线程为其加上锁以后,其他线程便不能再使用那个资源,除非被解锁。
程序实例
用一个取钱的程序例子,来说明为什么需要引入同步。在使用同步机制前,整体程序如下:
public class FetchMoneyTest { public static void main(String[] args) { Bank bank = new Bank(); Thread t1 = new MoneyThread(bank);// 从银行取钱 Thread t2 = new MoneyThread(bank);// 从取款机取钱 t1.start(); t2.start(); } } class Bank { private int money = 1000; public int getMoney(int number) { if (number < 0) { return -1; } else if (number > money) { return -2; } else if (money < 0) { return -3; } else { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } money -= number; System.out.println("Left Money: " + money); return number; } } } class MoneyThread extends Thread { private Bank bank; public MoneyThread(Bank bank) { this.bank = bank; } @Override public void run() { System.out.println(bank.getMoney(800)); } }
程序中定义了一个Bank类,其中包含了用户存储的钱(1000元),然后用两个线程进行取钱操作,可以看到尽管Bank类中的getMoney()方法对取钱数目与存款数据进行了判断,但是执行后,结果输出两个800,表明从两个线程中都成功地取出了800元钱。
这是为什么呢?因为getMoney()方法中有一些逻辑判断,进入最后一个else语句块后,有一个简短的休眠,那么在第一个线程休眠的过程中,第二个线程也成功进入了这个else语句块(因为存款的钱还没有取走),当两个线程结束休眠后,不再进行逻辑判断而是直接将钱取走,所以两个线程都取到了800元钱,此时money为负600。
需要注意这里并不能确定哪一个线程是第一个线程,哪一个线程是第二个线程,先后顺序是不定的。
在getMoney()方法中加入打印语句输出剩余的钱数,可以看到输出为剩余钱数为200,-600,或-600,-600。这是不一定的,因为可能在第一次输出剩余钱数之前,另一个线程可能还没有将钱取走,也可能已经取走。
解决办法
解决办法:在getMoney()方法上加上关键字synchronized。即程序改动后如下:(只是加了一个关键字)
改正后的程序例子
public class FetchMoneyTest { public static void main(String[] args) { Bank bank = new Bank(); Thread t1 = new MoneyThread(bank);// 从银行取钱 Thread t2 = new MoneyThread(bank);// 从取款机取钱 t1.start(); t2.start(); } } class Bank { private int money = 1000; public synchronized int getMoney(int number) { if (number < 0) { return -1; } else if (number > money) { return -2; } else if (money < 0) { return -3; } else { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } money -= number; System.out.println("Left Money: " + money); return number; } } } class MoneyThread extends Thread { private Bank bank; public MoneyThread(Bank bank) { this.bank = bank; } @Override public void run() { System.out.println(bank.getMoney(800)); } }
此时输出结果如下:
Left Money: 200
800
-2
表明第一次取款800元后,剩余200元,当另一个线程再去取的时候,已经不能再取钱了。
一个线程开始执行取钱的方法之后就阻止了其他线程再去执行这个方法,直到本线程结束,其他线程才有访问权利。
当synchronized关键字修饰一个方法的时候,该方法叫做同步方法。
Java中的每个对象都有一个锁(lock),或者叫做监视器(monitor),当一个线程访问某个对象的synchronized方法时,将该对象上锁,其他任何线程都无法再去访问该对象的synchronized方法了。直到之前的那个线程执行方法完毕后(或者是抛出了异常),才将该对象的锁释放掉,其他线程才有可能再去访问该对象的synchronized方法。
注意这时候是给对象上锁,如果是不同的对象,则各个对象之间没有限制关系。
参考资料
圣思园张龙老师Java SE系列视频教程。相关文章推荐
- Java 多线程 synchronized同步
- JAVA多线程(二)竞态条件、死锁及同步机制
- java 多线程 同步机制 总结(二)
- java多线程处理导入数据拆分List集合,同步处理插入数据
- Java多线程的同步
- Java的多线程之同步篇三:同步阻塞、监视器、volatile、final、原子性、线程局部变量、锁测试与超时、读写锁
- Java入门到精通——基础篇之多线程实现简单的PV操作的进程同步
- 黑马程序员——Java基础——多线程的同步、死锁和等待唤醒机制
- java-多线程-同步的优化
- 【Java多线程】同步辅助类CyclicBarrier
- java多线程处理导入数据拆分List集合,同步处理插入数据
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- java 多线程 同步类容器与并发类容器
- 【Java多线程】同步辅助类CountDownLatch
- Java_多线程(创建/同步锁/等待唤醒机制/线程池/AsyncTask)
- Java多线程-线程的同步与锁
- JAVA 多线程,同步机制
- Java多线程简析——Synchronized(同步锁)、Lock以及线程池
- java多线程——同步方法和同步代码块
- 【Java多线程】浅谈多线程机制(三)之互斥与同步