Java加锁的三种方法
wait和notify
package com.lockSupport;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
public class LockSupportTest {
public static void main(String[] args) {
test1();
}
/**
* 测试wait和notify方法
*/
public static void test1(){
Object o = new Object();
new Thread(()->{
synchronized (o){
System.out.println(Thread.currentThread().getName() + "\t ----come in!");
try {
o.wait();
} catch (Exception e){
e.printStackTrace();
}
}
}, "t1").start();
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(()->{
synchronized (o){
o.notify();
System.out.println(Thread.currentThread().getName() + "\t ---发出通知");
}
}, "t2").start();
}
}
await和signal
package com.lockSupport;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
/**
* todo:
* 1、wait和notify方法
* 2、Condition的await方法和signal方法
* 3、LockSupport的park和unpark
*
* 结论:一、1和2中的await和wait都需要先加锁再使用,否则报错
* 二、如果先唤醒再加锁 则会造成线程阻塞,无法被唤醒
* 三、park和unpark方法则没有上述限制,不加锁也能使用,顺序颠倒也不会影响线程被唤醒
*
*
*/
public class LockSupportTest {
public static void main(String[] args) {
test3();
}
/**
* 测试Condition的await方法和signal方法
*/
public static void test3(){
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
Thread t1 = new Thread(() -> {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "\t ----come in!");
condition.await();
System.out.println(Thread.currentThread().getName() + "\t ----被唤醒!");
} catch (Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}
}, "t1");
t1.start();
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(()->{
try {
lock.lock();
condition.signal();
System.out.println(Thread.currentThread().getName() + "\t ----发出通知!");
} catch (Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}
}, "t2").start();
}
}
park和unpark
package com.lockSupport;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
/**
* todo:
* 1、wait和notify方法
* 2、Condition的await方法和signal方法
* 3、LockSupport的park和unpark
*
* 结论:一、1和2中的await和wait都需要先加锁再使用,否则报错
* 二、如果先唤醒再加锁 则会造成线程阻塞,无法被唤醒
* 三、park和unpark方法则没有上述限制,不加锁也能使用,顺序颠倒也不会影响线程被唤醒
*
*
*/
public class LockSupportTest {
public static void main(String[] args) {
//test1();
//test2();
test3();
}
/**
* 测试Condition的await方法和signal方法
*/
public static void test3(){
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
Thread t1 = new Thread(() -> {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "\t ----come in!");
condition.await();
System.out.println(Thread.currentThread().getName() + "\t ----被唤醒!");
} catch (Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}
}, "t1");
t1.start();
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(()->{
try {
lock.lock();
condition.signal();
System.out.println(Thread.currentThread().getName() + "\t ----发出通知!");
} catch (Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}
}, "t2").start();
}
/**
* 测试LockSupport的park和unpark功能 这两个方法类似lock和unlock
*/
public static void test2(){
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t ----come in!");
// 线程会阻塞在此处 等待unpark方法执行后才会被唤醒
LockSupport.park();
System.out.println(Thread.currentThread().getName() + "\t ----被唤醒!");
}, "t1");
t1.start();
new Thread(()->{
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
LockSupport.unpark(t1);
System.out.println(Thread.currentThread().getName() + "\t ----发出通知!");
}, "t2").start();
}
/**
* 测试wait和notify方法
*/
public static void test1(){
Object o = new Object();
new Thread(()->{
synchronized (o){
System.out.println(Thread.currentThread().getName() + "\t ----come in!");
try {
o.wait();
} catch (Exception e){
e.printStackTrace();
}
}
}, "t1").start();
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(()->{
synchronized (o){
o.notify();
System.out.println(Thread.currentThread().getName() + "\t ---发出通知");
}
}, "t2").start();
}
}
总结
结论:
一、1和2中的await和wait都需要先加锁再使用,否则报错
二、如果先唤醒再加锁 则会造成线程阻塞,无法被唤醒
三、park和unpark方法则没有上述限制,不加锁也能使用,顺序颠倒也不会影响线程被唤醒