以前编程没有怎么接触过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方法。