synchronized关键字详解

  • 2019 年 10 月 30 日
  • 笔记

版权声明:本文为博主原创文章,遵循 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