synchronized关键字

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方法执行完毕

[color=blue]线程1和线程2会排队执行,因为他们都是要求同步的方法,而且他们会依赖于同一个实例,test。而synchronized (this)会锁定这个实例。需要注意的是:t1和方t2谁先抢到锁是随机的。[/color]
我们把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方法执行完毕

[color=blue]可以看到没有达到同步的效果,这是因为在线程t1,t2中,每次都是new Test(),运行的是不同的实例,大家各行其道![/color]
[b]要是这种情况也需要同步怎么办,这就要用到对象锁啦。我们把lock1和lock2方法的锁类型改一下[/b]

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对象锁被释放....

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

[b][size=medium]题外话,看看对象锁父类子类的关系。把lock1方法稍微改一下,锁定Test对象的父类Object对象,[/size][/b]

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对象锁被释放----

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

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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值