二者异同
- 两者都是可重入锁,都是独占锁。
- synchronized 依赖于 JVM 而 ReentrantLock 依赖于 API
- synchronized是非公平锁,而 ReentrantLock 既可以是公平锁,也可以是公平锁。
- ReentrantLock 是等待可中断、可选择性通知。
ReentrantLock 的newContion()
public class Solution {
static volatile int i = 0;
static final ReentrantLock LOCK = new ReentrantLock();
static final Condition condition = LOCK.newCondition();
public static void make() throws InterruptedException {
LOCK.lock();
if (i == 0) {
for (int i1 = 0; i1 < 5; i1++) {
Thread.sleep(100);
System.out.println("做了一个,哈哈哈");
}
i++;
condition.signal();
condition.await();
}
LOCK.unlock();
}
public static void consume() throws InterruptedException {
LOCK.lock();
try {
if (i != 0){
for (int i1 = 0; i1 < 5; i1++) {
Thread.sleep(500);
System.out.println("吃了一个,哈哈哈");
}
i--;
condition.signal();
condition.await();
}
}finally {
LOCK.unlock();
}
}
public static void main(String[] args) {
new Thread(()->{
while (true) {
try {
Thread.sleep(1000);
System.out.println(0);
make();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(()->{
while (true) {
System.out.println(1);
try {
Thread.sleep(1000);
System.out.println(0);
consume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
输出:
1
0
1
0
做了一个,哈哈哈
做了一个,哈哈哈
做了一个,哈哈哈
做了一个,哈哈哈
做了一个,哈哈哈
0
吃了一个,哈哈哈
吃了一个,哈哈哈
吃了一个,哈哈哈
吃了一个,哈哈哈
吃了一个,哈哈哈
0
做了一个,哈哈哈
做了一个,哈哈哈
做了一个,哈哈哈
做了一个,哈哈哈
做了一个,哈哈哈
1
0
吃了一个,哈哈哈
吃了一个,哈哈哈
吃了一个,哈哈哈
吃了一个,哈哈哈
吃了一个,哈哈哈
Synconsized的wait/notify方法
public class Solution {
static Queue<Integer> queue = new ArrayDeque<>();
public synchronized void make() throws InterruptedException {
while (queue.isEmpty()){
queue.add(1);
System.out.println("做了一个,哈哈哈");
}
notifyAll();
this.wait();
}
public synchronized void consume() throws InterruptedException {
while (!queue.isEmpty()){
queue.remove();
System.out.println("吃了一个,哈哈哈");
}
notifyAll();
this.wait();
}
public static void main(String[] args) {
Solution solution = new Solution();
new Thread(()->{
while (true) {
try {
Thread.sleep(1000);
//这里会一直执行
System.out.println(Thread.currentThread().getName());
solution.make();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(()->{
while (true) {
try {
Thread.sleep(1000);
//这里会一直执行
System.out.println(Thread.currentThread().getName());
solution.consume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
输出:
Thread-1
Thread-0
做了一个,哈哈哈
Thread-1
吃了一个,哈哈哈
Thread-0
做了一个,哈哈哈
Thread-1
吃了一个,哈哈哈
Thread-0
做了一个,哈哈哈
Thread-1
通过wait/notify方法以及ReentrantLock之Condition用于线程之间的通信,应该注意释放锁的对象
如果是实例方法,就是this释放
如果是静态方法,应该是 类.class 释放
例子
对对象使用正常
public synchronized void test(){
while (true) {
if (Thread.currentThread().getName().equals("weakup")) notifyAll();
try {
if (!Thread.currentThread().getName().equals("weakup")) wait();
Thread.sleep(500);
System.out.println("开始输出");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
Solution solution = new Solution();
for (int i = 0; i < 5; i++) {
Thread.sleep(500);
Thread thread = new Thread(() -> {
solution.test();
});
if (i == 4) {
thread.setName("weakup");
System.out.println("准备唤醒所有");
}
thread.start();
}
}
如果是类的话,就会报错,因此获取操作的对象不对,下面回去了线程对象了。
public static synchronized void test(){
while (true) {
// Thread.currentThread().notifyAll();回获取的是线程对象,不是类对象,对象使用错了
if (Thread.currentThread().getName().equals("weakup")) Thread.currentThread().notifyAll();
try {
if (!Thread.currentThread().getName().equals("weakup")) Thread.currentThread().wait();
Thread.sleep(500);
System.out.println("开始输出");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
因此会报错:
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at com.ll.mymailsever.utils.Solution.test(Solution.java:16)
at com.ll.mymailsever.utils.Solution.lambda$main$0(Solution.java:30)
at java.lang.Thread.run(Thread.java:745)
出现IllegalMonitorStateException情况
- 当前线程不含有当前对象的锁资源的时候,调用obj.wait()方法;
- 当前线程不含有当前对象的锁资源的时候,调用obj.notify()方法。
- 当前线程不含有当前对象的锁资源的时候,调用obj.notifyAll()方法。
修改为:
public static synchronized void test(){
while (true) {
//此时是释放当前的类对象的锁
if (Thread.currentThread().getName().equals("weakup")) Solution.class.notifyAll();
try {
if (!Thread.currentThread().getName().equals("weakup")) Solution.class.wait();
Thread.sleep(500);
System.out.println("开始输出");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
参考:
异常