1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Java多线程----java 对象锁(synchronized/lock)

Java多线程----java 对象锁(synchronized/lock)

时间:2021-10-11 16:37:54

相关推荐

Java多线程----java 对象锁(synchronized/lock)

在并发环境下,解决共享资源冲突问题时,可以考虑使用锁机制。

1. 对象锁

所有对象都自动含有单一的锁。

JVM负责跟踪对象被加锁的次数。如果一个对象被解锁,其计数变为0。在任务(线程)第一次给对象加锁的时候,计数变为1。每当这个相同的任务(线程)在此对象上获得锁时,计数会递增。

只有首先获得锁的任务(线程)才能继续获取该对象上的多个锁。

每当任务离开一个synchronized方法,计数递减,当计数为0的时候,锁被完全释放,此时别的任务就可以使用此资源。

被syncronized修饰的方法,是对类的对象加锁,也就是说,当对象访问该方法时,当前的对象会被加锁,同一时刻同一对象不能再访问该方法,或者该对象的其他被syncronized修饰的方法。不同对象,同一时刻可以访问同一个syncronized方法或其他syncronized方法,两个对象之间并不产生互斥关系。

2. 类锁

对于同步静态方法/静态变量互斥体,由于一个class不论被实例化多少次,其中的静态方法和静态变量在内存中都只由一份。所以,一旦一个静态的方法被申明为synchronized。此类所有的实例化对象在调用此方法,共用同一把锁,我们称之为类锁。一旦一个静态变量被作为synchronized block的互斥体。进入此同步区域时,都要先获得此静态变量的对象锁。

由上述同步静态方法引申出一个概念,那就是类锁。其实系统中并不存在什么类锁。当一个同步静态方法被调用时,系统获取的其实就是代表该类的类对象的对象锁

被static、syncronized修饰的方法,是对类进行加锁,也就是说,同一时刻只有一个类能访问该方法。对象锁与类锁不会产生互斥关系。

可以尝试用以下方式获取类锁

[java]view plain copysynchronized(xxx.class){...}synchronized(Class.forName("xxx")){...} 若要同时获取两种锁,同时获取类锁和对象锁是允许的,并不会产生任何问题,但使用类锁时一定要注意,一旦产生类锁的嵌套获取的话,就会产生死锁,因为每个class在内存中都只能生成一个Class实例对象。

3. synchronized同步块

3.1. 同步到单一对象锁

当使用同步块时,如果方法下的同步块都同步到一个对象上的锁,则所有的任务(线程)只能互斥的进入这些同步块。

Resource1.java演示了三个线程(包括main线程)试图进入某个类的三个不同的方法的同步块中,虽然这些同步块处在不同的方法中,但由于是同步到同一个对象(当前对象 synchronized (this)),所以对它们的方法依然是互斥的。

Resource1.java

[java]view plain copypackagecom.zj.lock;importjava.util.concurrent.TimeUnit;publicclassResource1{publicvoidf(){ //otheroperationsshouldnotbelocked... System.out.println(Thread.currentThread().getName() +":notsynchronizedinf()");synchronized(this){for(inti=0;i<5;i++){ System.out.println(Thread.currentThread().getName() +":synchronizedinf()");try{ TimeUnit.SECONDS.sleep(3); }catch(InterruptedExceptione){ e.printStackTrace(); } } } }publicvoidg(){ //otheroperationsshouldnotbelocked... System.out.println(Thread.currentThread().getName() +":notsynchronizeding()");synchronized(this){for(inti=0;i<5;i++){ System.out.println(Thread.currentThread().getName() +":synchronizeding()");try{ TimeUnit.SECONDS.sleep(3); }catch(InterruptedExceptione){ e.printStackTrace(); } } } }publicvoidh(){ //otheroperationsshouldnotbelocked... System.out.println(Thread.currentThread().getName() +":notsynchronizedinh()");synchronized(this){for(inti=0;i<5;i++){ System.out.println(Thread.currentThread().getName() +":synchronizedinh()");try{ TimeUnit.SECONDS.sleep(3); }catch(InterruptedExceptione){ e.printStackTrace(); } } } }publicstaticvoidmain(String[]args){finalResource1rs=newResource1();newThread(){publicvoidrun(){ rs.f(); } }.start();newThread(){publicvoidrun(){ rs.g(); } }.start(); rs.h(); } } 结果:

Thread-0:not synchronized in f()

Thread-0:synchronized in f()

main:not synchronized in h()

Thread-1:not synchronized in g()

Thread-0:synchronized in f()

Thread-0:synchronized in f()

Thread-0:synchronized in f()

Thread-0:synchronized in f()

Thread-1:synchronized in g()

Thread-1:synchronized in g()

Thread-1:synchronized in g()

Thread-1:synchronized in g()

Thread-1:synchronized in g()

main:synchronized in h()

main:synchronized in h()

main:synchronized in h()

main:synchronized in h()

main:synchronized in h()

3.2. 同步到多个对象锁

Resource1.java演示了三个线程(包括main线程)试图进入某个类的三个不同的方法的同步块中,这些同步块处在不同的方法中,并且是同步到三个不同的对象(synchronized (this),synchronized(syncObject1),synchronized (syncObject2)),所以对它们的方法中的临界资源访问是独立的。

Resource2.java

[java]view plain copypackagecom.zj.lock;importjava.util.concurrent.TimeUnit;publicclassResource2{privateObjectsyncObject1=newObject();privateObjectsyncObject2=newObject();publicvoidf(){ //otheroperationsshouldnotbelocked... System.out.println(Thread.currentThread().getName() +":notsynchronizedinf()");synchronized(this){for(inti=0;i<5;i++){ System.out.println(Thread.currentThread().getName() +":synchronizedinf()");try{ TimeUnit.SECONDS.sleep(3); }catch(InterruptedExceptione){ e.printStackTrace(); } } } }publicvoidg(){ //otheroperationsshouldnotbelocked... System.out.println(Thread.currentThread().getName() +":notsynchronizeding()");synchronized(syncObject1){for(inti=0;i<5;i++){ System.out.println(Thread.currentThread().getName() +":synchronizeding()");try{ TimeUnit.SECONDS.sleep(3); }catch(InterruptedExceptione){ e.printStackTrace(); } } } }publicvoidh(){ //otheroperationsshouldnotbelocked... System.out.println(Thread.currentThread().getName() +":notsynchronizedinh()");synchronized(syncObject2){for(inti=0;i<5;i++){ System.out.println(Thread.currentThread().getName() +":synchronizedinh()");try{ TimeUnit.SECONDS.sleep(3); }catch(InterruptedExceptione){ e.printStackTrace(); } } } }publicstaticvoidmain(String[]args){finalResource2rs=newResource2();newThread(){publicvoidrun(){ rs.f(); } }.start();newThread(){publicvoidrun(){ rs.g(); } }.start(); rs.h(); } } 结果:

Thread-0:not synchronized in f()

Thread-0:synchronized in f()

main:not synchronized in h()

main:synchronized in h()

Thread-1:not synchronized in g()

Thread-1:synchronized in g()

Thread-0:synchronized in f()

main:synchronized in h()

Thread-1:synchronized in g()

Thread-0:synchronized in f()

main:synchronized in h()

Thread-1:synchronized in g()

Thread-0:synchronized in f()

main:synchronized in h()

Thread-1:synchronized in g()

Thread-0:synchronized in f()

main:synchronized in h()

Thread-1:synchronized in g()

4. Lock对象锁

除了使用synchronized外,还可以使用Lock对象来创建临界区。Resource3.java的演示效果同Resource1.java;Resource4.java的演示效果同Resource2.java。

Resource3.java

[java]view plain copypackagecom.zj.lock;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;publicclassResource3{privateLocklock=newReentrantLock();publicvoidf(){ //otheroperationsshouldnotbelocked... System.out.println(Thread.currentThread().getName() +":notsynchronizedinf()"); lock.lock();try{for(inti=0;i<5;i++){ System.out.println(Thread.currentThread().getName() +":synchronizedinf()");try{ TimeUnit.SECONDS.sleep(3); }catch(InterruptedExceptione){ e.printStackTrace(); } } }finally{ lock.unlock(); } }publicvoidg(){ //otheroperationsshouldnotbelocked... System.out.println(Thread.currentThread().getName() +":notsynchronizeding()"); lock.lock();try{for(inti=0;i<5;i++){ System.out.println(Thread.currentThread().getName() +":synchronizeding()");try{ TimeUnit.SECONDS.sleep(3); }catch(InterruptedExceptione){ e.printStackTrace(); } } }finally{ lock.unlock(); } }publicvoidh(){ //otheroperationsshouldnotbelocked... System.out.println(Thread.currentThread().getName() +":notsynchronizedinh()"); lock.lock();try{for(inti=0;i<5;i++){ System.out.println(Thread.currentThread().getName() +":synchronizedinh()");try{ TimeUnit.SECONDS.sleep(3); }catch(InterruptedExceptione){ e.printStackTrace(); } } }finally{ lock.unlock(); } }publicstaticvoidmain(String[]args){finalResource3rs=newResource3();newThread(){publicvoidrun(){ rs.f(); } }.start();newThread(){publicvoidrun(){ rs.g(); } }.start(); rs.h(); } 结果:

Thread-0:not synchronized in f()

Thread-0:synchronized in f()

main:not synchronized in h()

Thread-1:not synchronized in g()

Thread-0:synchronized in f()

Thread-0:synchronized in f()

Thread-0:synchronized in f()

Thread-0:synchronized in f()

main:synchronized in h()

main:synchronized in h()

main:synchronized in h()

main:synchronized in h()

main:synchronized in h()

Thread-1:synchronized in g()

Thread-1:synchronized in g()

Thread-1:synchronized in g()

Thread-1:synchronized in g()

Thread-1:synchronized in g()

Resource4.java

[java]view plain copypackagecom.zj.lock;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;publicclassResource4{privateLocklock1=newReentrantLock();privateLocklock2=newReentrantLock();privateLocklock3=newReentrantLock();publicvoidf(){ //otheroperationsshouldnotbelocked... System.out.println(Thread.currentThread().getName() +":notsynchronizedinf()"); lock1.lock();try{for(inti=0;i<5;i++){ System.out.println(Thread.currentThread().getName() +":synchronizedinf()");try{ TimeUnit.SECONDS.sleep(3); }catch(InterruptedExceptione){ e.printStackTrace(); } } }finally{ lock1.unlock(); } }publicvoidg(){ //otheroperationsshouldnotbelocked... System.out.println(Thread.currentThread().getName() +":notsynchronizeding()"); lock2.lock();try{for(inti=0;i<5;i++){ System.out.println(Thread.currentThread().getName() +":synchronizeding()");try{ TimeUnit.SECONDS.sleep(3); }catch(InterruptedExceptione){ e.printStackTrace(); } } }finally{ lock2.unlock(); } }publicvoidh(){ //otheroperationsshouldnotbelocked... System.out.println(Thread.currentThread().getName() +":notsynchronizedinh()"); lock3.lock();try{for(inti=0;i<5;i++){ System.out.println(Thread.currentThread().getName() +":synchronizedinh()");try{ TimeUnit.SECONDS.sleep(3); }catch(InterruptedExceptione){ e.printStackTrace(); } } }finally{ lock3.unlock(); } }publicstaticvoidmain(String[]args){finalResource4rs=newResource4();newThread(){publicvoidrun(){ rs.f(); } }.start();newThread(){publicvoidrun(){ rs.g(); } }.start(); rs.h(); } } 结果:

Thread-0:not synchronized in f()

Thread-0:synchronized in f()

main:not synchronized in h()

main:synchronized in h()

Thread-1:not synchronized in g()

Thread-1:synchronized in g()

Thread-0:synchronized in f()

main:synchronized in h()

Thread-1:synchronized in g()

Thread-0:synchronized in f()

main:synchronized in h()

Thread-1:synchronized in g()

Thread-0:synchronized in f()

main:synchronized in h()

Thread-1:synchronized in g()

Thread-0:synchronized in f()

main:synchronized in h()

Thread-1:synchronized in g()

另外,ReentrantLock可定时和可轮询的锁获取模式由tryLock方法实现。

[java]view plain copypublicbooleantryLock();//等同于tryLock(0,TimeUnit.SECONDS),不停询问是否可获取锁publicbooleantryLock(longtimeout, TimeUnitunit)throwsInterruptedException//timeout-等待锁的时间,unit-timeout参数的时间单位

5. synchronized和lock的区别:

Lock 的锁定是通过代码实现的,而 synchronized 是在 JVM 层面上实现的。

synchronized 在锁定时如果方法块抛出异常,JVM 会自动将锁释放掉,不会因为出了异常没有释放锁造成线程死锁。但是 Lock 的话就享受不到 JVM 带来自动的功能,出现异常时必须在 finally 将锁释放掉,否则将会引起死锁。

在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。

ReentrantLock:

ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。

Atomic:

和上面的类似,不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。

6、sleep() 和 wait() 有什么区别?

sleep是让线程指定休眠时间,然后继续工作

wait则是等待,直到有线程通知notify()唤醒他才会重新工作。

notify()、 notifyAll 方法

无法指定。选择是任意性的。

唤醒在此对象监视器上等待的单个线程。如果有多个线程都在此对象上等待,则会选择唤醒其中一个线程。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。