以前编程没有怎么接触过synchronized方法,不太了解,今天编程遇到了多个线程访问同一个共享资源的问题,google了下synchronized使用方法,网上有二种说法,第一种说法是当一个线程访问了某个对象中的synchronzied方法,其它线程可以继续访问其它的synchronized方法,第二个说法与第一种说法相反,不能访问。搞的我也不确定,更要命的是,这两种说法在网上一边又一边的转载,以讹传讹,要误导不少java新手。到底那一个是正确的,编个程序验证就清楚了。
下面是一个示例程序,有三个角色,一个家庭中的父亲,母亲,和儿子,同时在ATM取款机上向同一个银行账号进行取钱和查询的操作
1.银行类
- package com.sunnylocus.test;
- public class Bank {
- private int money = 100;
- //取钱
- public synchronized void takeMoney(int num) {
- Thread.sleep(1000 * 5); //取钱需要5秒
- money -= num;
- }
- //存钱
- public synchronized void addMoney(int num) {
- Thread.sleep(1000 * 10); //存钱需要10秒
- money += money;
- }
- //查询
- public int queryMoney() {
- return money;
- }
- }
2.父亲类
- package com.sunnylocus.test;
- import java.text.DateFormat;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- public class Father extends Thread{
- private Bank bank;
- private int num;
- DateFormat dateFormate = new SimpleDateFormat("a h:mm:ss"); //日期格式对象
- public Father(Bank bank,int num) {
- this.bank = bank;
- this.num = num;
- }
- public void run() {
- System.out.println("老爸正在取钱... --"+dateFormate.format(new Date()));
- bank.takeMoney(num);
- System.out.println("老爸取走了"+num +" --"+dateFormate.format(new Date()));
- }
- }
3.母亲类
- package com.sunnylocus.test;
- import java.text.DateFormat;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- public class Monther extends Thread{
- private Bank bank;
- private int num;
- DateFormat dateFormate = new SimpleDateFormat("a h:mm:ss"); //日期格式对象
- public Monther(Bank bank,int num) {
- this.bank = bank;
- this.num = num;
- }
- public void run() {
- System.out.println("老妈正在取钱.... "+dateFormate.format(new Date()));
- bank.takeMoney(num);
- System.out.println("老妈取走了"+num+" --"+dateFormate.format(new Date()));
- }
- }
4.儿子类
- package com.sunnylocus.test;
- import java.text.DateFormat;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- public class Sun extends Thread{
- private Bank bank;
- DateFormat dateFormate = new SimpleDateFormat("a h:mm:ss"); //日期格式对象
- public Sun(Bank bank) {
- this.bank = bank;
- }
- public void run() {
- //查询余款
- System.out.println("儿子查询余额:"+bank.queryMoney() +" --"+dateFormate.format(new Date()));
- }
- }
5.测试类
- package com.sunnylocus.test;
- public class Main {
- public static void main(String[] args) {
- //银行
- Bank bank = new Bank();
- //老爸
- Father father = new Father(bank,50);
- //老妈
- Monther monther = new Monther(bank,100);
- //儿子
- Sun sun = new Sun(bank);
- new Thread(father).start();
- new Thread(monther).start();
- new Thread(sun).start();
- }
- }
输出结果:
- 老爸正在取钱... --上午 11:52:01
- 老妈正在取钱.... --上午 11:52:01
- 儿子查询余额:100 --上午 11:52:01
- 老爸取走了50 --上午 11:52:06
- 老妈取了30 --上午 11:52:11
一共有三个线程,同时启动,父亲线程和母亲线程同时取款的操作,因为父亲线程已经占用了对象锁,所以母亲线程只能等到父亲执行完方法释放锁后,才能执行。即便父亲线程占用了对象锁,儿子线程也能调用非synchronzied方法
我们把母亲类的取钱的方法改成存钱的操作,虽然不是同一个synchronized方法.也一样不能执行,必须等到父亲线程方法执行完毕后,才能进行存钱的操作
我的结论:
synchronized method(){}可以防止多个线程同时访问这个对象的synchronized方法,如果一个对象有多个synchronized方法,只要一个线 程访问了其中的一个synchronized方法,那么其它线程不能同时访问这个对象中的任何一个synchronized方法,但可以访问这个对象中的非synchronized方法。