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
警告:因为这个方法是在内存级别的锁定,不同于数据库的硬盘级,所以只有在单机情况下有那么点意义!!。事实上,有这种并发级别的商城,肯定都是分布式的了。
分享到:
相关推荐
java同步synchronized关键字用法示例
java多线程中synchronized关键字的用法 解压密码 www.jiangyea.com
synchronized关键字在java中的重要性 以及常用的方法 还有它的详解
Synchronized关键字的用法
Lock接口与synchronized关键字在Java并发编程中都是用于实现同步机制的重要工具,但它们在使用方式、功能特性以及灵活性等方面存在一些显著的差异。 首先,从使用方式上来看,synchronized是Java语言内置的关键字,...
java基本教程之synchronized关键字java多线程教程共19页.pdf.zip
并发编程原理学习:synchronized关键字.doc
java的线程同步机制synchronized关键字的理解_.docx
java synchronized关键字原理、自定义一把锁来实现同步等
Java多线程synchronized关键字详解(六)共5页.pdf.zip
线程安全,使用synchronized关键字
【Java并发编程】Synchronized关键字实现原理.doc
5-4JVM内置锁synchronized关键字详解.mp4
实例解析Java中的synchronized关键字与线程平安问题_.docx
【ASP.NET编程知识】实例解析Java中的synchronized关键字与线程安全问题.docx
主要介绍了Java中synchronized关键字的用法,针对synchronized修饰方法的使用作出了简单讲解和演示,需要的朋友可以参考下
Java并发编程---synchronized关键
NULL 博文链接:https://seandsky-boyy-163-com.iteye.com/blog/1340783
开启了10个线程,每个线程都累加了10000000次,如果结果正确的话总数应该是10*10000000=1000000000.可是运行多次结果都不是这个数,而且每次运行结果都不一样。 线程安全问题主要来源于JMM的设计,主要集中在主内存...