版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/luo4105/article/details/68069426
synchronized可以是线程的同步锁,可以修饰方法,也可以修饰代码块。作用是当多个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。但是多个并发线程访问多个对象调用这个锁住的方法时,同步锁不会产生作用。比如以下错误代码。
public class SyncTest {
public static void main(String[] args) {
Thread t1 = new Thread(){ //取钱线程
public void run(){
Bank b1 = new Bank();
try {
b1.getMoney((double)50);
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
};
Thread t2 = new Thread(){ //存钱线程
public void run(){
Bank b1 = new Bank();
try {
b1.saveMoney((double)100);
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
};
t2.start();
t1.start();
}
}
class Bank {
private static Double money = new Double(0);
/**
* 取钱
* @param money
* @throws Exception
*/
public synchronized void getMoney(Double m) throws Exception {
if(Bank.money <= 0) {
throw new Exception("错误提示1:卡上余额数据错误,当前余额为" + Bank.money + "元");
}
if(Bank.money < money) {
throw new Exception("错误提示1:卡上余额不足,当前余额为" + Bank.money + "元");
}
else {
Bank.money = Bank.money - money;
System.out.println("成功取出" + money + "元,当前余额为" + Bank.money + "元");
}
}
/**
* 存钱
* @param m
* @throws Exception
*/
public synchronized void saveMoney(Double m) throws Exception {
if(money < 0) {
throw new Exception("卡上余额不足,当前余额为" + Bank.money + "元");
}
else {
Bank.money = money + m;
System.out.println("成功存入" + m + "元,当前余额为" + Bank.money + "元");
}
}
}
虽然Bank类的getMoney()方法和saveMoney()方法都使用synchronized 关键字进行同步锁,但是在线程t1、t2中,同步的现象并没有发生,因为在t1、t2线程中重新给Bank实例化。是两个对象去执行同步锁方法,不是一个对象执行其同步锁方法,所以同步不会起效果。 正确的写法 1.两个线程调用同一个Bank对象。把Bank bank = new Bank()放在t1、t2实例化之前,t1、t2中的run方法都调用bank运行getMoney()和saveMoney()才能保证同步运行。 改正代码如下,在第3行、6行、16行对代码进行修改。
public static void main(String[] args) {
Bank b1 = new Bank();
Thread t1 = new Thread(){ //取钱线程
public void run(){
try {
b1.getMoney((double)50);
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
};
Thread t2 = new Thread(){ //存钱线程
public void run(){
try {
b1.saveMoney((double)100);
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
};
t2.start();
t1.start();
}
2.两个线程调用两个Bank对象,但是Bank类中getMoney()方法和saveMoney()方法的同步锁锁的对象是private static Double money这个属性。即去掉getMoney()方法和saveMoney()方法的synchronized关键字,在方法内用synchronized(money){}将方法的语句块锁起来。这样,锁的是Bank.money这个对象,在getMoney()和saveMoney()方法同时调用Bank.money这个对象这个类对象时,同步锁就会起到作用。 改正代码如下,在第7行、27行去掉synchronized关键字修饰符,在第8、28行加上了synchronized(money){同步修饰代码段。
private static Double money = new Double(0);
/**
* 取钱
* @param money
* @throws Exception
*/
public void getMoney(Double m) throws Exception {
synchronized(money){
if(Bank.money <= 0) {
throw new Exception("错误提示1:卡上余额数据错误,当前余额为" + Bank.money + "元");
}
if(Bank.money < money) {
throw new Exception("错误提示1:卡上余额不足,当前余额为" + Bank.money + "元");
}
else {
Bank.money = Bank.money - money;
System.out.println("成功取出" + money + "元,当前余额为" + Bank.money + "元");
}
}
}
/**
* 存钱
* @param m
* @throws Exception
*/
public void saveMoney(Double m) throws Exception {
synchronized(money){
if(money < 0) {
throw new Exception("卡上余额不足,当前余额为" + Bank.money + "元");
}
else {
Bank.money = money + m;
System.out.println("成功存入" + m + "元,当前余额为" + Bank.money + "元");
}
}
}
3.将两个方法改为静态方法。这样,同步锁锁的是Bank这个类对象,在t1、t2线程中调用的也是同样的Bank类对象方法。这样也能达到同步的效果。 改正代码如下,在第7行、27行方法加上static修饰符。
private static Double money = new Double(0);
/**
* 取钱
* @param money
* @throws Exception
*/
public synchronized static void getMoney(Double m) throws Exception {
if(Bank.money <= 0) {
throw new Exception("错误提示1:卡上余额数据错误,当前余额为" + Bank.money + "元");
}
if(Bank.money < money) {
throw new Exception("错误提示1:卡上余额不足,当前余额为" + Bank.money + "元");
}
else {
Bank.money = Bank.money - money;
System.out.println("成功取出" + money + "元,当前余额为" + Bank.money + "元");
}
}
/**
* 存钱
* @param m
* @throws Exception
*/
public synchronized static void saveMoney(Double m) throws Exception {
if(money < 0) {
throw new Exception("卡上余额不足,当前余额为" + Bank.money + "元");
}
else {
Bank.money = money + m;
System.out.println("成功存入" + m + "元,当前余额为" + Bank.money + "元");
}
}
参考资料 [1].http://www.cnblogs.com/QQParadise/articles/5059824.html