标签:member time monitor sign opened format 进不去 row current
调用wait()和notify()的线程必须是已经获取了synchronized对象锁(注意这里是对象锁不是类锁也就是说被static标记的方法是不行的)的线程。否则将会抛出java.lang.IllegalMonitorStateException
wait方法会主动让出已经获取到的synchronized锁,使得当前线程阻塞。所以如果线程没有获取到synchronized锁就调用wait()或者notify()就会报错,另外调用wait()和notify()的对象必须要和synchronized
是同一个对象。
以下四种代码都是错误的。
public class Demo2 {
public static void main(String[] args) {
Object lock = new Object();
Demo2 demo = new Demo2();
Thread t1 = new Thread(() -> {
demo.testa(lock);
});
t1.start();
}
public void testa(Object lock) {
try {
//错误的
this.wait();
System.out.println("aaaaaaaaaaaaaa");
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
public class Demo2 {
public static void main(String[] args) {
Object lock = new Object();
Demo2 demo = new Demo2();
Thread t1 = new Thread(() -> {
demo.testa(lock);
});
t1.start();
}
public void testa(Object lock) {
try {
//错误的
this.notify();
System.out.println("aaaaaaaaaaaaaa");
} catch (Exception e) {
System.out.println(e);
}
}
}
public class Demo2 {
public static void main(String[] args) {
Object lock = new Object();
Demo2 demo = new Demo2();
Thread t1 = new Thread(() -> {
demo.testa(lock);
});
t1.start();
}
public void testa(Object lock) {
synchronized (lock) {
try {
//调用wait的对象是this而synchronized当前是Object对象锁
this.wait();
System.out.println("aaaaaaaaaaaaaa");
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
}
public class Demo2 {
public static void main(String[] args) {
Object lock = new Object();
Demo2 demo = new Demo2();
Thread t1 = new Thread(() -> {
demo.testa(lock);
});
t1.start();
}
public void testa(Object lock) {
synchronized (lock) {
try {
//synchronized使用的是Object锁而调用notify()的是this对象。
this.notify();
System.out.println("aaaaaaaaaaaaaa");
} catch (Exception e) {
System.out.println(e);
}
}
}
}
调用此方法将当前线程进入阻塞状态,并且让出锁,直到另一个线程调用该对象的notify()
方法或notifyAll()
方法。
public class Demo1 {
public static void main(String[] args) throws Exception {
Demo1 demo1 = new Demo1();
Thread t1 = new Thread(() -> {
demo1.exc();
});
t1.start();
Thread t2 = new Thread(() -> {
demo1.exc2();
});
t2.start();
}
public synchronized void exc() {
try {
wait();
} catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("aaa");
}
public synchronized void exc2() {
System.out.println("bbb");
}
}
以上代码片段t1和t2两个线程都使用的是demo1这个对象的锁。t1执行后获取到了锁,然后调用wait()后自身便处于了阻塞状态,t2线程获得了demo1对象锁并执行结束。
在这段代码中t1不会只会一直阻塞因为没有线程使用demo1的notify(),t1线程也没有被中断。
指定的时间后线程将重新恢复就绪状态,拥有争夺锁的权力。参数单位为毫秒。
public class Demo1 {
public static void main(String[] args) throws Exception {
Demo1 demo1 = new Demo1();
Thread t1 = new Thread(() -> {
demo1.exc();
});
t1.start();
Thread t2 = new Thread(() -> {
demo1.exc2();
});
t2.start();
}
public synchronized void exc() {
try {
wait(3000);
} catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("aaa");
}
public synchronized void exc2() {
try {
Thread.sleep(5000);
} catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("bbb");
}
}
以上代码片段t1线程执行后会阻塞直到3秒后将重新恢复就绪状态,但此时锁被t2获取正在执行,直到t2执行结束后释放锁,t1继续执行。
这个重载方法除了毫秒外还允许传递一个int类型的纳秒值,取值范围是0-999999。纳秒和毫秒的换算是1毫秒=1000000纳秒。也就是说第二个参数最多接近于1毫秒。
public class Demo1 {
public static void main(String[] args) throws Exception {
Demo1 demo1 = new Demo1();
Thread t1 = new Thread(() -> {
demo1.exc();
});
t1.start();
Thread t2 = new Thread(() -> {
demo1.exc2();
});
//t2.start();
}
public synchronized void exc() {
try {
System.out.println(System.currentTimeMillis());
wait(3000,999999);
System.out.println(System.currentTimeMillis());
} catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("aaa");
}
public synchronized void exc2() {
System.out.println("bbb");
}
}
以上代码片段只执行了t1,t1线程在阻塞前和阻塞后的时间差大概为3016毫秒。
public class Demo1 {
public static void main(String[] args) {
Object lock = new Object();
Demo1 demo = new Demo1();
Thread t1 = new Thread(() -> {
demo.testa(lock);
});
Thread t2 = new Thread(() -> {
demo.testb(lock);
});
t1.start();
try {
Thread.sleep(1000);
} catch (Exception e) {
}
t2.start();
}
public synchronized void testa(Object lock) {
System.out.println("aaaaaaaaaaaaaa1");
synchronized (lock) {
System.out.println("aaaaaaaaaaaaaa2");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void testb(Object lock) {
System.out.println("bbbbbbbbbbbbbbbbbbb1");
synchronized (lock) {
System.out.println("bbbbbbbbbbbbbbbbbbb2");
}
}
}
以上代码片段testa()和testb()两个方法上有synchronized方法内部还有synchronized (lock){}。在main()中线程1执行a方法线程2执行b方法。最终的执行结果是:
aaaaaaaaaaaaaa1
aaaaaaaaaaaaaa2
bbbbbbbbbbbbbbbbbbb1
出现这个结果的原因是线程1执行a方法时先拿到this锁也就是Demo对象的锁,又拿到了lock这个锁(也就是Object这个对象的锁)然后wait()执行后释放了this锁,为什么释放的是this锁?因为wait()默认使用的对象是this。也就是this.wait();
线程2执行b方法获取了this锁,但是无法拿到lock对象锁,所以进不去代码块。
public class Demo1 {
public static void main(String[] args) {
Object lock = new Object();
Demo1 demo = new Demo1();
Thread t1 = new Thread(() -> {
demo.testa(lock);
});
Thread t2 = new Thread(() -> {
demo.testb(lock);
});
t1.start();
try {
Thread.sleep(1000);
} catch (Exception e) {
}
t2.start();
}
public synchronized void testa(Object lock) {
System.out.println("aaaaaaaaaaaaaa1");
synchronized (lock) {
System.out.println("aaaaaaaaaaaaaa2");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void testb(Object lock) {
System.out.println("bbbbbbbbbbbbbbbbbbb1");
synchronized (lock) {
System.out.println("bbbbbbbbbbbbbbbbbbb2");
}
}
}
将代码稍稍修改,wait()由lock对象调用。执行结果是:
aaaaaaaaaaaaaa1
aaaaaaaaaaaaaa2
结果不出意料,lock.wait()释放了lock这个对象锁。线程2执行b方法拿不到this锁第一层都进不去。
public class Demo1 {
public static void main(String[] args) {
Object lock = new Object();
Demo1 demo = new Demo1();
Thread t1 = new Thread(() -> {
demo.testa(lock);
});
Thread t2 = new Thread(() -> {
demo.testb(lock);
});
t1.start();
try {
Thread.sleep(1000);
} catch (Exception e) {
}
t2.start();
}
public synchronized void testa(Object lock) {
System.out.println("aaaaaaaaaaaaaa1");
synchronized (this) {
System.out.println("aaaaaaaaaaaaaa2");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void testb(Object lock) {
System.out.println("bbbbbbbbbbbbbbbbbbb1");
synchronized (lock) {
System.out.println("bbbbbbbbbbbbbbbbbbb2");
}
}
}
将a方法中synchronized代码块的锁修改为this。此时a方法中的两个锁都是this。执行wait()释放this锁。线程2执行b方法可以获取this锁,同时lock对象锁占用也可以获取所以打印结果是:
aaaaaaaaaaaaaa1
aaaaaaaaaaaaaa2
bbbbbbbbbbbbbbbbbbb1
bbbbbbbbbbbbbbbbbbb2
唤醒正在等待对象监控的单个线程。
public class Demo1 {
public static void main(String[] args) {
Object lock = new Object();
Demo1 demo = new Demo1();
Thread t1 = new Thread(() -> {
demo.testa(lock);
});
Thread t2 = new Thread(() -> {
demo.testb(lock);
});
Thread t3 = new Thread(() -> {
demo.testc(lock);
});
t2.start();
t1.start();
try {
Thread.sleep(1000);
}catch (Exception e) {
}
t3.start();
}
public synchronized void testa(Object lock) {
try {
this.wait();
System.out.println("aaaaaaaaaaaaaa");
} catch (InterruptedException e) {
System.out.println(e);
}
}
public synchronized void testb(Object lock) {
try {
this.wait();
System.out.println("bbbbbbbbbbbbbb");
} catch (InterruptedException e) {
System.out.println(e);
}
}
public void testc(Object lock) {
synchronized (this) {
try {
this.notify();
} catch (Exception e) {
System.out.println(e);
}
}
}
}
以上代码片段线程1和线程2执行a,b方法。而a,b方法都调用了this.wait()也就是说t1和t2线程都是被this对象锁阻塞了。线程3调用this.notify()会唤醒t1,t2中的一个阻塞线程。
public class Demo1 {
public static void main(String[] args) {
Object lock = new Object();
Demo1 demo = new Demo1();
Thread t1 = new Thread(() -> {
demo.testa(lock);
});
Thread t2 = new Thread(() -> {
demo.testb(lock);
});
Thread t3 = new Thread(() -> {
demo.testc(lock);
});
t2.start();
t1.start();
try {
Thread.sleep(1000);
}catch (Exception e) {
}
t3.start();
}
public synchronized void testa(Object lock) {
try {
this.wait();
System.out.println("aaaaaaaaaaaaaa");
} catch (InterruptedException e) {
System.out.println(e);
}
}
public synchronized void testb(Object lock) {
try {
this.wait();
System.out.println("bbbbbbbbbbbbbb");
} catch (InterruptedException e) {
System.out.println(e);
}
}
public void testc(Object lock) {
synchronized (lock) {
try {
lock.notify();
} catch (Exception e) {
System.out.println(e);
}
}
}
}
将c方法中的锁更改为lock对象,notify()方法也由lock对象调用则t1,t2两个线程都不会被唤醒。因为notify()唤醒的线程只能是被和自身同一个对象锁阻塞的线程。
另外如果c方法的synchronized是this锁而调用notify()的是其他对象则也会报错。
唤醒正在等待对象监控的所有线程。
public class Demo1 {
public static void main(String[] args) {
Object lock = new Object();
Demo1 demo = new Demo1();
Thread t1 = new Thread(() -> {
demo.testa(lock);
});
Thread t2 = new Thread(() -> {
demo.testb(lock);
});
Thread t3 = new Thread(() -> {
demo.testc(lock);
});
t2.start();
t1.start();
try {
Thread.sleep(1000);
}catch (Exception e) {
}
t3.start();
}
public synchronized void testa(Object lock) {
try {
this.wait();
System.out.println("aaaaaaaaaaaaaa");
} catch (InterruptedException e) {
System.out.println(e);
}
}
public synchronized void testb(Object lock) {
try {
this.wait();
System.out.println("bbbbbbbbbbbbbb");
} catch (InterruptedException e) {
System.out.println(e);
}
}
public void testc(Object lock) {
synchronized (this) {
try {
this.notifyAll();
} catch (Exception e) {
System.out.println(e);
}
}
}
}
以上代码将notify()更换成了notifyAll()则t1,和t2线程都会被唤醒。
condition接口它的功能其实和Object中的wait()notify()方法的作用是一样的。wait()使线程进入阻塞状态notify()解除线程的阻塞状态它们要配合synchronized使用。
也就是说只有被synchronized锁住的代码块内才可以使用wait()和notify()。
condition接口提供了await();使用线程进入阻塞状态sigal()解除线程阻塞状态。则是配合Lock接口使用的。
Lock.newCondition()方法获取一个Condition接口的实现类。
await()和signal()必须要在lock()方法后,并且调用await()signal()的Condition对象必须和lock()方法是同一组内的。也就是说一个Lock对象要和Condition对象是成对使用
的。这和wait()notify()方法必须和synchronized锁是同一个对象锁是一样的。
以下四种写法都是错误的。
public class Demo2 {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public static void main(String[] args) {
Demo2 demo = new Demo2();
Thread t1 = new Thread(()->{
demo.a();
});
t1.start();
}
public void a() {
try {
condition.await();
System.out.println("aaaaaaaaaaaa");
} catch (Exception e) {
System.out.println(e);
}
}
}
public class Demo2 {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public static void main(String[] args) {
Demo2 demo = new Demo2();
Thread t1 = new Thread(()->{
demo.a();
});
t1.start();
}
public void a() {
try {
condition.signal();
System.out.println("aaaaaaaaaaaa");
} catch (Exception e) {
System.out.println(e);
}
}
}
public class Demo2 {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
ReentrantLock lock2 = new ReentrantLock();
Condition condition2 = lock2.newCondition();
public static void main(String[] args) {
Demo2 demo = new Demo2();
Thread t1 = new Thread(()->{
demo.a();
});
t1.start();
}
public void a() {
try {
lock.lock();
condition2.await();
System.out.println("aaaaaaaaaaaa");
} catch (Exception e) {
System.out.println(e);
}
}
}
public class Demo2 {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
ReentrantLock lock2 = new ReentrantLock();
Condition condition2 = lock2.newCondition();
public static void main(String[] args) {
Demo2 demo = new Demo2();
Thread t1 = new Thread(()->{
demo.a();
});
t1.start();
}
public void a() {
try {
lock.lock();
condition2.signal();
System.out.println("aaaaaaaaaaaa");
} catch (Exception e) {
System.out.println(e);
}
}
}
使当前线程阻塞直到中断或被signal()方法唤醒。
public class Demo2 {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public static void main(String[] args) {
Demo2 demo = new Demo2();
Thread t1 = new Thread(() -> {
demo.a();
});
Thread t2 = new Thread(() -> {
demo.b();
});
t1.start();
try {
Thread.sleep(1000 * 1);
} catch (Exception e) {
e.printStackTrace();
}
t2.start();
}
public void a() {
try {
lock.lock();
condition.await();
System.out.println("aaaaaaaaaaaa");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void b() {
try {
lock.lock();
System.out.println("bbbbbbbbbbbbbb");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
以上代码执行结果是t1线程被阻塞不会执行输出,t2线程会正常结束。t1线程执行a()方法后获取lock锁然后await()会将当前线程阻塞并且释放lock锁。t2线程获取锁输出结果后释放锁,但t1线程始终无人唤醒。
这个重载方法给除了一个等待时间和时间单位。如果在指定时间结束后线程没有被signal()方法唤醒也没有中断则会自动被唤醒。
public class Demo2 { ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); public static void main(String[] args) { Demo2 demo = new Demo2(); Thread t1 = new Thread(() -> { demo.a(); }); Thread t2 = new Thread(() -> { demo.b(); }); t1.start(); try { Thread.sleep(1000 * 1); } catch (Exception e) { e.printStackTrace(); } t2.start(); } public void a() { try { lock.lock(); condition.await(3,TimeUnit.SECONDS); System.out.println("aaaaaaaaaaaa"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void b() { try { lock.lock(); System.out.println("bbbbbbbbbbbbbb"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
以上方法t1线程阻塞后释放lock锁,t2线程获取锁在执行完毕后释放lock锁。t1线程在3秒后自动唤醒然后获取lock锁执行代码。
awaitNanos(timeout)
这个重载方法以纳秒为单位的时间单位。
public class Demo2 { ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); public static void main(String[] args) { Demo2 demo = new Demo2(); Thread t1 = new Thread(() -> { demo.a(); }); Thread t2 = new Thread(() -> { demo.b(); }); t1.start(); try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } t2.start(); } public void a() { try { lock.lock(); condition.awaitNanos(3000000000L); System.out.println("aaaaaaaaaaaa"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void b() { try { lock.lock(); System.out.println("bbbbbbbbbbbbbb"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
以上代码片段3000000000L纳秒也就是3秒它的执行效果和condition.await(3,TimeUnit.SECONDS)是相同的。
awaitUntil(Date)
这个重载方法接收一个Date时间,表示在指定的时间到达后自动唤醒线程。
public class Demo2 { ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); public static void main(String[] args) { Demo2 demo = new Demo2(); Thread t1 = new Thread(() -> { demo.a(); }); Thread t2 = new Thread(() -> { demo.b(); }); t1.start(); try { Thread.sleep(1000 * 1); } catch (Exception e) { e.printStackTrace(); } t2.start(); } public void a() { try { lock.lock(); SimpleDateFormat sm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date parse = sm.parse("2021-01-23 22:35:00"); condition.awaitUntil(parse); System.out.println("aaaaaaaaaaaa"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void b() { try { lock.lock(); System.out.println("bbbbbbbbbbbbbb"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
以上代码t2线程会在时间到达后获取锁并执行完毕。
以上4个使线程阻塞的方法如果在阻塞过程中线程被调用interrupt()则会接收到一个InterruptedException异常。而awaitUninterruptibly()阻塞方法被中断则不会接收到异常。
public class Demo2 { ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); public static void main(String[] args) { Demo2 demo = new Demo2(); Thread t1 = new Thread(() -> { demo.a(); }); Thread t2 = new Thread(() -> { demo.b(); }); t1.start(); try { Thread.sleep(1000 * 1); } catch (Exception e) { e.printStackTrace(); } t2.start(); try { Thread.sleep(1000 * 1); } catch (Exception e) { e.printStackTrace(); } t1.interrupt(); } public void a() { try { lock.lock(); condition.await(); System.out.println("aaaaaaaaaaaa"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void b() { try { lock.lock(); System.out.println("bbbbbbbbbbbbbb"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
public class Demo2 { ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); public static void main(String[] args) { Demo2 demo = new Demo2(); Thread t1 = new Thread(() -> { demo.a(); }); Thread t2 = new Thread(() -> { demo.b(); }); t1.start(); try { Thread.sleep(1000 * 1); } catch (Exception e) { e.printStackTrace(); } t2.start(); try { Thread.sleep(1000 * 1); } catch (Exception e) { e.printStackTrace(); } t1.interrupt(); } public void a() { try { lock.lock(); condition.awaitUninterruptibly(); System.out.println("aaaaaaaaaaaa"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void b() { try { lock.lock(); System.out.println("bbbbbbbbbbbbbb"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
以上两个代码片段第一个会接收到InterruptedException异常第二个则不会。
signal()唤醒一个被当前lock锁阻塞的线程。它从await()阻塞队列中获取阻塞时间最长的线程将其唤醒。
public class Demo2 { ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); public static void main(String[] args) { Demo2 demo = new Demo2(); Thread t1 = new Thread(() -> { demo.a(); }); Thread t2 = new Thread(() -> { demo.b(); }); Thread t3 = new Thread(() -> { demo.c(); }); t2.start(); t1.start(); try { Thread.sleep(1000 * 1); } catch (Exception e) { e.printStackTrace(); } t3.start(); } public void a() { try { lock.lock(); condition.await(); System.out.println("aaaaaaaaaaaa"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void b() { try { lock.lock(); condition.await(); System.out.println("bbbbbbbbbbbbbbbbb"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void c() { try { lock.lock(); System.out.println("ccccccccccc"); condition.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
以上代码片段t3线程执行后会释放阻塞队列中阻塞时间最长的线程也就是t2线程,t1线程不会被唤醒。
signal()唤醒所有被当前lock锁阻塞的线程。
public class Demo2 { ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); public static void main(String[] args) { Demo2 demo = new Demo2(); Thread t1 = new Thread(() -> { demo.a(); }); Thread t2 = new Thread(() -> { demo.b(); }); Thread t3 = new Thread(() -> { demo.c(); }); t2.start(); t1.start(); try { Thread.sleep(1000 * 1); } catch (Exception e) { e.printStackTrace(); } t3.start(); } public void a() { try { lock.lock(); condition.await(); System.out.println("aaaaaaaaaaaa"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void b() { try { lock.lock(); condition.await(); System.out.println("bbbbbbbbbbbbbbbbb"); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void c() { try { lock.lock(); System.out.println("ccccccccccc"); condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
以上代码t3线程执行后会将t2,t1线程全部唤醒。
标签:member time monitor sign opened format 进不去 row current
原文地址:https://www.cnblogs.com/zumengjie/p/14312549.html