Java synchronized 探索

一 并发的需求

 

java的开发中,经常会有多线程的使用,在多线程使用时,就不可避免要访问同一个变量,这时就需要对共享变量进行控制,防止对一个变量同时访问时出错,在java中有synchronized关键字及其他方法进行并行控制,这里对synchronized进行一个介绍,首先引入一个例子,说明并发控制的必要性。

例:假设一家公司有n个部门,每个部门都要给一个人发工资,用一个int变量money代表一个人的工资,现在每个部门用一个线程给这个人加工资,如果不加控制,我们对这个人发工资时,用如下代码,Person代表人,add()方法对该人进行加工资,另外用一个AddTask类表示多线程:

 

 

public class Person {
	static int money = 0;
	
	public  void add(){
			money += 10;
			money -= 10;
			money += 10;
	}
	
	public static void main(String []args){
		Person person = new Person();
		Thread []myTask = new Thread[100];
		AddTask addTask = new AddTask(person);
		// 100个线程,每个线程都给加工资100;
		for (int i = 0 ; i< 100 ;i ++){
			myTask[i] = new Thread(addTask);
			myTask[i].start();
		}
		// 等待所有线程执行完毕,如果所有线程不join(),会有可能出现主线程比其他线程先执行完毕,导致最后的结果仍然不正确
		for (int i = 0 ; i< 100 ;i ++){
			try {
				myTask[i].join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("The money is "+money);
	}
}

public class AddTask implements Runnable {

	Person person;
	public AddTask(Person person){
		this.person = person;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		person.add();
	}

}

结果如下:

The money is 990

 

工资发生了错误,当然这是偶然情况,但是偶然的发生就说明了问题的所在。

因为多个线程同时访问工资变量时,出现的问题。

 

二 Java内部锁(Intrinsic Locks或Monitor Lock)

因为java synchronized 用到了java 内部锁,先对内部锁进行简单介绍。JavaObject类中就有Intrinsic lock,和wait(),notify()一样,因此所有对象都有这个锁。在java中可以对任意一个对象请求他的内部锁,如果获取成功,则程序正常执行;如果获取失败,(即已经被其他线程申请走了)就阻塞,直至其他线程使用释放该锁。

Java也有Lock类,这里不做介绍。

 

三 Synchronized 介绍

对于需要同步变量如何解决呢?用synchronized关键字,synchronized关键字主要有两种使用方法:

 

1 synchronized 修饰方法

当一个线程调用synchronized方法时,自动获取方法所在对象(!!)的锁,方法返回时释放锁。对于static方法,也是一样的,只不过由于static属于类所有,java的类对应一个Class object,调用static synchronized方法时,获取Class object的锁,返回时释放。

如下对add()方法加上synchronized关键字时,其他线程访问add()时,需要先获取person对象的锁。所有的线程在初始化时传入同一个person对象,将来访问add()时,都需要先获取该person对象的锁,防止同步时出错。


public class Person {
	static int money = 0;
	
	public synchronized  void add(){
			money += 10;
			money -= 10;
			money += 10;
	}
	
	public static void main(String []args){
		Person person = new Person();
		Thread []myTask = new Thread[100];
		AddTask addTask = new AddTask(person);
		// 100个线程,每个线程都给加工资100;
		for (int i = 0 ; i< 100 ;i ++){
			myTask[i] = new Thread(addTask);
			myTask[i].start();
		}
		// 等待所有线程执行完毕
		for (int i = 0 ; i< 100 ;i ++){
			try {
				myTask[i].join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("The money is "+money);
	}
}

 

 

2 synchronized 语句,在oracle中叫synchronized statement

这种情况synchronized必须指明提供锁的对象,比如this,指的是当前所在的对象,也可以是其他对象。而且需要注意的时,所有线程必须用synchronized指定的是同一个对象。如下代码也可以解决同步的问题。

public class Person {
	static int money = 0;
	
	public   void add(){
		synchronized(this){
			money += 10;
			money -= 10;
			money += 10;
		}
	}
	
	public static void main(String []args){
		Person person = new Person();
		Thread []myTask = new Thread[100];
		AddTask addTask = new AddTask(person);
		// 100个线程,每个线程都给加工资100;
		for (int i = 0 ; i< 100 ;i ++){
			myTask[i] = new Thread(addTask);
			myTask[i].start();
		}
		// 等待所有线程执行完毕
		for (int i = 0 ; i< 100 ;i ++){
			try {
				myTask[i].join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("The money is "+money);
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值