package test;
public class Tiger3 {
static class Inner {
private Thread thread = null;
private int count = 0;
public synchronized void getLock() {
while(tryGetLock() == false) { //无限循环,如果没有其他线程通过释放锁来唤醒它,它永不会退出,因为它无法自己终止while循环。当别的线程调用notify()释放锁后,它会继续执行这次wait()以后的代码,也即会再一次调用tryGetLock()方法来尝试获得锁。
System.out.println(Thread.currentThread().getName() + "is waited!");
try {
wait();
} catch (InterruptedException e) {
// TODO: handle exception
}
System.out.println(Thread.currentThread().getName() + " is notified!");
}
}
/*
假设在线程一获得锁以后,线程二试图获得锁,这时因为thread 是指向第一个线程的,所以条件一(thread == null)不匹配。这时因为Thread.currentThread()指向的是线程二,而thread 指向的是线程一,所以条件二(thread == Thread.currentThread())也不匹配。然后,getLock()中的wait()方法将会被调用,当前线程(线程二)会暂时陷入wait()状态。直到线程一执行事务完毕后调用freeLock()中的notify()方法释放锁,线程二才被激活。
所以这个机制的真实意图是通过控制对当前线程句柄的引用来达到调度线程的目的。因此它直接操作的不是帐户或ATM对象,而是当前线程本身。*/
private synchronized boolean tryGetLock() {
boolean istrue = false;
if (thread == null) { //获得对当前线程的一个引用。
thread = Thread.currentThread();
istrue = true;
}
if (thread == Thread.currentThread()) { //这个条件的设置是为了模拟当前已经获得锁的线程重复尝试获得锁的努力。比如,一个ATM接连重复几次对一个帐户进行存取交易。如果没有设置这个条件,当一个线程第一次调用getLock()获得琐以后马上又再一次调用getLock()试图获得锁,那么wait()方法将会被执行,锁将会被错误地释放。如果所有的线程都如此执行,那么到最后很可能会发生所有线程都在wait()的情形。
istrue = true;
count ++;
}
return istrue;
}
public synchronized void freeLock() {
if (thread == Thread.currentThread()) {
count--; // 模拟当前线程在重复尝试获得锁以后重复尝试释放锁。
if (count == 0) {
thread = null;
notify();
System.out.println(Thread.currentThread().getName() + " call notify()!");
}
}
}
public synchronized void m() {
System.out.println(Thread.currentThread().getName() + " begin m()");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + " end m()");
}
}
public static void main(String[] args) {
final Inner in = new Inner();
Thread[] ts = new Thread[10];
for (int i = 0; i < ts.length; i++) {
ts[i] = new Thread(
new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + ".start()************");
in.getLock(); //模拟重复处理事务
in.m();
in.getLock(); //模拟重复处理事务
in.m();
in.freeLock();
in.freeLock();
System.out.println(Thread.currentThread().getName() + ".end()+++++++++++++");
}
}, "T" + i
);
}
for (Thread t :ts) {
t.start();
}
}
}
结果:
T0.start()************
T0 begin m()
T1.start()************
T2.start()************
T3.start()************
T4.start()************
T5.start()************
T6.start()************
T7.start()************
T8.start()************
T9.start()************
T0 end m()
T1is waited!
T2is waited!
T3is waited!
T4is waited!
T5is waited!
T6is waited!
T7is waited!
T8is waited!
T9is waited!
T0 begin m()
T0 end m()
T0 call notify()!
T1 is notified!
T1 begin m()
T0.end()+++++++++++++
T1 end m()
T1 begin m()
T1 end m()
T1 call notify()!
T2 is notified!
T2 begin m()
T1.end()+++++++++++++
T2 end m()
T2 begin m()
T2 end m()
T2 call notify()!
T3 is notified!
T3 begin m()
T2.end()+++++++++++++
T3 end m()
T3 begin m()
T3 end m()
T3 call notify()!
T4 is notified!
T4 begin m()
T3.end()+++++++++++++
T4 end m()
T4 begin m()
T4 end m()
T4 call notify()!
T5 is notified!
T5 begin m()
T4.end()+++++++++++++
T5 end m()
T5 begin m()
T5 end m()
T5 call notify()!
T6 is notified!
T6 begin m()
T5.end()+++++++++++++
T6 end m()
T6 begin m()
T6 end m()
T6 call notify()!
T7 is notified!
T7 begin m()
T6.end()+++++++++++++
T7 end m()
T7 begin m()
T7 end m()
T7 call notify()!
T7.end()+++++++++++++
T8 is notified!
T8 begin m()
T8 end m()
T8 begin m()
T8 end m()
T8 call notify()!
T8.end()+++++++++++++
T9 is notified!
T9 begin m()
T9 end m()
T9 begin m()
T9 end m()
T9 call notify()!
T9.end()+++++++++++++
分析:
十个线程几乎同时被启动,但当线程0获得锁以后,其他九个就马上被阻塞了。直到线程0执行完毕并释放锁,并用notify()方法唤醒九个waiting中的线程中的一个。结果中,Tn.end()++++++++++++行的出现有些错位,这是因为在打印这行内容之前,线程Tn已经释放了锁,而打印这行内容的语句并没有位于synchronized块中,因而是非线程安全的。
如果修改代码变成这样:
private synchronized boolean tryGetLock() {
boolean istrue = false;
if (thread == null) {
thread = Thread.currentThread();
istrue = true;
}
//if (thread == Thread.currentThread()) {
//istrue = true;
//count ++;
//}
return istrue;
}
public synchronized void freeLock() {
if (thread == Thread.currentThread()) {
//count--;
//if (count == 0) {
thread = null;
notify();
System.out.println(Thread.currentThread().getName() + " call notify()!");
//}
}
}
T0.start()************
T0 begin m()
T1.start()************
T2.start()************
T3.start()************
T4.start()************
T5.start()************
T6.start()************
T7.start()************
T8.start()************
T9.start()************
T0 end m()
T1is waited!
T2is waited!
T3is waited!
T4is waited!
T5is waited!
T6is waited!
T7is waited!
T8is waited!
T9is waited!
T0is waited!
分析:因为T0重复调用getLock()却没有释放锁,所以最后导致所有线程都被阻塞,陷入“死锁”状态。
如果修改代码如下:
for (int i = 0; i < ts.length; i++) {
ts[i] = new Thread(
new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName() + ".start()************");
in.getLock();
in.m1();
in.m2();
in.m3();
in.m4();
in.freeLock();
System.out.println(Thread.currentThread().getName() + ".end()+++++++++++++");
}
}, "T" + i
);
}
其中m1(),m2(),m3(),m4()拷贝自前面的m()方法。
结果:
T0.start()************
T0 begin m1()
T1.start()************
T2.start()************
T3.start()************
T4.start()************
T5.start()************
T6.start()************
T7.start()************
T8.start()************
T9.start()************
T0 end m1()
T1is waited!
T2is waited!
T3is waited!
T4is waited!
T5is waited!
T6is waited!
T7is waited!
T8is waited!
T9is waited!
T0 begin m2()
T0 end m2()
T0 begin m3()
T0 end m3()
T0 begin m4()
T0 end m4()
T0 call notify()!
T1 is notified!
T1 begin m1()
T0.end()+++++++++++++
T1 end m1()
T1 begin m2()
T1 end m2()
T1 begin m3()
T1 end m3()
T1 begin m4()
T1 end m4()
T1 call notify()!
T2 is notified!
T2 begin m1()
T1.end()+++++++++++++
T2 end m1()
T2 begin m2()
T2 end m2()
T2 begin m3()
T2 end m3()
T2 begin m4()
T2 end m4()
T2 call notify()!
T3 is notified!
T3 begin m1()
T2.end()+++++++++++++
T3 end m1()
T3 begin m2()
T3 end m2()
T3 begin m3()
T3 end m3()
T3 begin m4()
T3 end m4()
T3 call notify()!
T4 is notified!
T4 begin m1()
T3.end()+++++++++++++
T4 end m1()
T4 begin m2()
T4 end m2()
T4 begin m3()
T4 end m3()
T4 begin m4()
T4 end m4()
T4 call notify()!
T5 is notified!
T4.end()+++++++++++++
T5 begin m1()
T5 end m1()
T5 begin m2()
T5 end m2()
T5 begin m3()
T5 end m3()
T5 begin m4()
T5 end m4()
T5 call notify()!
T6 is notified!
T6 begin m1()
T5.end()+++++++++++++
T6 end m1()
T6 begin m2()
T6 end m2()
T6 begin m3()
T6 end m3()
T6 begin m4()
T6 end m4()
T6 call notify()!
T7 is notified!
T7 begin m1()
T6.end()+++++++++++++
T7 end m1()
T7 begin m2()
T7 end m2()
T7 begin m3()
T7 end m3()
T7 begin m4()
T7 end m4()
T7 call notify()!
T8 is notified!
T8 begin m1()
T7.end()+++++++++++++
T8 end m1()
T8 begin m2()
T8 end m2()
T8 begin m3()
T8 end m3()
T8 begin m4()
T8 end m4()
T8 call notify()!
T9 is notified!
T9 begin m1()
T8.end()+++++++++++++
T9 end m1()
T9 begin m2()
T9 end m2()
T9 begin m3()
T9 end m3()
T9 begin m4()
T9 end m4()
T9 call notify()!
T9.end()+++++++++++++
分析:
一、可以看得很清楚,在Tn调用四个方法过程中,其它线程是无法接触到这四个方法的。这是单单声明synchronized语句块所不能达到的效果:synchronized可以保护在一个线程执行某一同步块的过程中其它线程无法执行其它同步块,但当该线程执行完这个同步块以后要想继续执行其它同步块时呢?这时候可能其它线程突然跑过来把锁给夺走了。而Lock()和Unlock()机制要解决的正是这个问题。
二、因为Lock()和Unlock()机制控制的不是普通对象,而是线程本身,所以m1(),m2(),m3(),m4()是否是synchronized的就没多大关系了。这是因为任何线程想要执行这四个方法都必须通过getLock()这个方法获得“许可”。而在同一段时间内,永远只有一个线程能获得这种“许可”调用这四个方法。
分享到:
相关推荐
描述中提到的“LOCK与UNLOCK的方法产生临界”,是指在多线程环境中创建一种临界区,使得在同一时间只有一个线程可以访问和修改TFDMemTable的数据,避免了数据竞争和不一致的问题。 在Delphi中,我们可以使用内置的...
用于加密和解密文本文件
AndroidLockUnlock ... ##这是什么?... 在这里,您可以看到AndroidLockUnlock如何使您的生活更轻松。... 将lockunlock.bat重命名为lockunlock.exe 将其拖到任务栏 将lockunlock.exe重命名回lockunlock.bat S
lock与unlock: lock尝试加锁,如果加锁不成功,线程阻塞,阻塞到持有该互斥量的其他线程解锁为止。 unlock主动解锁函数,同时将阻塞在该锁上的所有线程全部唤醒,至于哪个线程先被唤醒,取决于优先级、调度。默认...
在本文中,我们将深入探讨 Nova 的两种重启方式——Soft Reboot 和 Hard Reboot,以及 Lock 和 Unlock 功能,这些都是管理和维护云实例的重要操作。 首先,让我们了解一下 Soft Reboot 和 Hard Reboot: 1. **Soft...
Lock接口提供了比synchronized更丰富的功能,如尝试获取锁(tryLock)、可中断的锁获取(lockInterruptibly)、超时获取锁(tryLock(long time, TimeUnit unit))以及显式解锁(unlock)。Lock接口的实现类,例如...
总结来说,JavaLock与Condition提供了高级的并发控制手段,能够帮助开发者设计出更高效、更可控的多线程程序。通过ReentrantLock的灵活配置和Condition的精细调度,可以解决许多复杂的同步问题。在实际开发中,应...
### Lock接口与synchronized关键字详解 #### 一、概述 在Java并发编程中,Lock接口与synchronized关键字都是实现同步的重要工具。它们虽然都用于控制多线程对共享资源的访问,但在使用方式、功能特性及灵活性方面...
Using android phone to establish a connection with your Mac via Bluetooth low-energy (BLE), controlling Mac lock state (Lock or Unlock). Features Store the password in Mac system keychain. Send the ...
在IT行业的专业知识中,解锁SIM卡锁定(simlock)是移动设备管理中一个常见的操作,尤其是在处理MTK(联发科)芯片组的手机时。本文将深入解析如何使用META工具进行MTK手机的SIM卡锁定解锁过程,该方法特别适用于...
lock.unlock(); // 无论是否抛出异常,都会释放锁 } ``` 此外,`Lock`接口还支持更复杂的并发控制策略,如可中断的锁等待(`tryLock()`方法),以及通过`Condition`对象实现线程间的条件等待和精确唤醒。 在实际...
pthread_mutex_unlock(&lock); } ``` 当需要访问共享资源时,调用`lock_data()`函数,这会使当前线程阻塞,直到获取到锁;访问完资源后,调用`unlock_data()`释放锁,让其他等待的线程有机会获得锁并继续执行。 ...
lock.unlock(); // 释放锁 } ``` 四、最佳实践 1. **合理设置超时时间**:根据业务需求设置合适的超时时间,避免长时间占用锁资源。 2. **避免死锁**:合理设计锁的获取顺序,避免出现循环等待的情况。 3. **...
大多数这些文件用于配置 KEYS 用户空间帮助程序层,以根据其 CID 向任何 SD/MMC 设备的内核驱动程序返回密码。 CID 是一个 32 位的十六进制字符串,保证对任何设备都是唯一的,并且可以通过为连接到第一个 MMC 主机...
使用ReentrantLock需要显式地调用lock()和unlock()方法。在尝试获取锁时,应将代码放入try-finally块中,以确保无论发生什么异常,都能正确释放锁。基本用法如下: ```java Lock lock = new ReentrantLock(); lock....
有助于在 Ubuntu 中捕获锁定/解锁事件的脚本。 在 Ubuntu 14.04 上测试如何使用或克隆脚本。 根据您的目的更改函数do_if_locked和do_if_unlocked 。 开始 $ ./event_catcher.sh start停止 $ ./event_catcher.sh stop
4. `spin_lock_bh(spinlock_t *lock)`:与 `spin_lock` 类似,但在获取锁时会禁止软中断。适用于需要在持有锁的同时禁止软中断的场景。 5. `spin_unlock_bh(spinlock_t *lock)`:对应于 `spin_lock_bh` 的解锁操作,...