`
supben
  • 浏览: 326847 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

synchronized关键字

    博客分类:
  • JVM
 
阅读更多
synchronized 分为对象锁,和实例锁。

先看实例锁:

public class Test {

	private void lock1() {
		synchronized (this) {
			try {
				System.out.println("lock1方法开始执行");
				Thread.sleep(5000);
			} catch (Exception e) {

			}
			System.out.println("lock1方法执行完毕");
		}
	}

	private void lock2() {
		synchronized (this) {
			try {
				System.out.println("lock2方法开始执行");
				Thread.sleep(1000);
			} catch (Exception e) {

			}
			System.out.println("lock2方法执行完毕");
		}
	}

	public static void main(String[] args) {
		final Test test = new Test();
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				test.lock1();
			}
		});

		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				test.lock2();
			}
		});

		t1.start();
		t2.start();
	}
}



运行结果:
lock1方法开始执行
lock1方法执行完毕
lock2方法开始执行
lock2方法执行完毕

线程1和线程2会排队执行,因为他们都是要求同步的方法,而且他们会依赖于同一个实例,test。而synchronized (this)会锁定这个实例。需要注意的是:t1和方t2谁先抢到锁是随机的。
我们把main方法改一改
public static void main(String[] args) {
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				new Test().lock1();
			}
		});

		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				new Test().lock2();
			}
		});

		t1.start();
		t2.start();
	}


运行结果:
lock2方法开始执行
lock1方法开始执行
lock2方法执行完毕
lock1方法执行完毕

可以看到没有达到同步的效果,这是因为在线程t1,t2中,每次都是new Test(),运行的是不同的实例,大家各行其道!
要是这种情况也需要同步怎么办,这就要用到对象锁啦。我们把lock1和lock2方法的锁类型改一下
	private void lock1() {
		synchronized (Test.class) {
			try {
				System.out.println("lock1方法开始执行,Test对象类被锁定----");
				Thread.sleep(5000);
			} catch (Exception e) {

			}
			System.out.println("lock1方法执行完毕,Test对象锁被释放----");
		}
	}

	private void lock2() {
		synchronized (Test.class) {
			try {
				System.out.println("lock2方法开始执行,Test对象类被锁定....");
				Thread.sleep(1000);
			} catch (Exception e) {

			}
			System.out.println("lock2方法执行完毕,Test对象锁被释放....");
		}
	}


执行结果:
lock1方法开始执行,Test对象类被锁定----
lock1方法执行完毕,Test对象锁被释放----
lock2方法开始执行,Test对象类被锁定....
lock2方法执行完毕,Test对象锁被释放....

可以看到, 在线程t1,t2中,我们都是new 不同的 test实例来执行,但是lock1方法和lock2方法仍然会排队执行。一旦一个方法比如lock1先抢到了锁,lock2会等待lock1完全执行完毕,才开始执行。就是说对象锁,锁定了所有对象的所有实例!

题外话,看看对象锁父类子类的关系。把lock1方法稍微改一下,锁定Test对象的父类Object对象,
	private void lock1() {
		synchronized (Object.class) {
			try {
				System.out.println("lock1方法开始执行,Object对象类被锁定----");
				Thread.sleep(5000);
			} catch (Exception e) {

			}
			System.out.println("lock1方法执行完毕,Object对象锁被释放----");
		}
	}


运行结果:
lock1方法开始执行,Object对象类被锁定----
lock2方法开始执行,Test对象类被锁定....
lock2方法执行完毕,Test对象锁被释放....
lock1方法执行完毕,Object对象锁被释放----

lock1和lock2方法会插队执行。结果表明对于锁来说,父类是父类,子类是子类,没有一点关系。

此外 synchronized 关键词还有一种是加在方法上,但是一般很少使用,因为一般来说,不是方法里的所有代码都会同步!对于加在普通方法上的同步,完全等价于synchronized(this), 对于加在静态方法上的同步,完全等价于对象锁synchronized(this.getClass()),此处不提。

现实生活中,经常有的一种需求是,处于对象锁与实例锁之间,假如说,我有一个Product,id是100,某个时刻只允许一个人修改这条数据,类似于数据库的行锁,java也可以实现这种需求。

首先绝对不能用对象锁锁Product.class,否则同一时刻,只能操作一个商品。这是绝对不能接受的!而且从实际出发id=99和id=100的实例我们也完全不需要同步!

但是可能同一个时刻在很多地方都有id=100的Product实例,典型的是在web环境中,多个请求(即多个线程)同时购买一个商品,要修改这个商品库存!我们想把Product的所有id=100的实例的库存同步!
我们可以用 map的 key,value特性来做这个事!详情参阅http://supben.iteye.com/blog/1416404


警告:因为这个方法是在内存级别的锁定,不同于数据库的硬盘级,所以只有在单机情况下有那么点意义!!。事实上,有这种并发级别的商城,肯定都是分布式的了。
0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics