java并发

This commit is contained in:
luoxiang 2019-11-26 23:28:26 +08:00
parent 3884f30ffd
commit fdb2e9404c
3 changed files with 152 additions and 47 deletions

View File

@ -17,9 +17,9 @@ public class AwaitAndSignal {
try { try {
lock.lock(); lock.lock();
String threadName = Thread.currentThread().getName(); String threadName = Thread.currentThread().getName();
System.out.println(threadName + "等待通知..."); System.out.println(threadName + "线程等待通知...");
condition.await(); condition.await();
System.out.println(threadName + "获得锁"); System.out.println(threadName + "线程后续操作");
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
@ -31,9 +31,10 @@ public class AwaitAndSignal {
public static void main(String[] args) throws InterruptedException { public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new IncreaseTask()); Thread thread1 = new Thread(new IncreaseTask());
thread1.start(); thread1.start();
Thread.sleep(2000); Thread.sleep(1000);
// 必须要再次获取该重入锁否则会抛出IllegalMonitorStateException异常 System.out.println("主线程开始操作");
lock.lock(); lock.lock();
System.out.println("主线程唤醒");
condition.signal(); condition.signal();
lock.unlock(); lock.unlock();
} }

View File

@ -36,7 +36,6 @@ public class J5_NotifyAll {
System.out.println("对象object唤醒"); System.out.println("对象object唤醒");
// 如果是object.notify()则是随机唤醒任意一个等待 // 如果是object.notify()则是随机唤醒任意一个等待
object.notifyAll(); object.notifyAll();
} }
}).start(); }).start();
} }

View File

@ -453,48 +453,6 @@ ReentrantLock 即支持公平锁也支持非公平锁,公平锁在调度时候
private static ReentrantLock fairLock = new ReentrantLock(true); private static ReentrantLock fairLock = new ReentrantLock(true);
``` ```
ReentrantLock 锁通常可以配合 `condition` 来使用,从而实现有条件的等待,示例如下:
```java
public class AwaitAndSignal {
private static ReentrantLock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
static class IncreaseTask implements Runnable {
@Override
public void run() {
try {
lock.lock();
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "等待通知...");
condition.await();
System.out.println(threadName + "获得锁");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new IncreaseTask());
thread1.start();
Thread.sleep(2000);
// 必须要再次获取该重入锁否则会抛出IllegalMonitorStateException异常
lock.lock();
condition.signal();
lock.unlock();
}
}
// 输出
Thread-0等待通知...
// 睡眠2秒...
Thread-0获得锁
```
### 6.3 读写锁 ### 6.3 读写锁
由于锁的排它性,导致多个线程无法以安全的方式并发地读取共享变量,这不利于提高系统的并发能力,因此产生了读写锁: 由于锁的排它性,导致多个线程无法以安全的方式并发地读取共享变量,这不利于提高系统的并发能力,因此产生了读写锁:
@ -599,8 +557,155 @@ public class ReadWriteLock {
### 7.1 等待与通知 ### 7.1 等待与通知
为了支持多线程之间的协作JDK 中提供了两个非常重要的方法:`wait()``notify()` ,这两个方法定义在 `Object` 类中,这意味着任何 Java 对象都可以调用者两个方法。如果一个线程调用了 `object.wait()` 方法,那么它就会进入该对象的等待队列中,这个队列中可能包含了多个线程,此时代表多个线程都在等待同一个对象;当 `object.notify()` 方法被调用时,它就会从这个等待队列中**随机**唤醒一个线程。
需要特别注意的是在调用这两个方法时,它们都必须位于对应对象的 synchronzied 语句中,因为这两个对象在调用前都需要获得对应对象的监视器,过程如下:
TODO
使用示例如下:
```java
public class J3_WaitAndNotify {
private static final Object object = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (object) {
try {
System.out.println("对象object等待");
object.wait();
System.out.println("线程1后续操作");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
synchronized (object) {
System.out.println("线程2开始操作");
System.out.println("对象object唤醒");
object.notify();
}
}).start();
}
}
// 输出
对象object等待
线程2开始操作
对象object唤醒
线程1后续操作
```
`notify()` 表示随机唤醒任意一个等待线程,如果想要唤醒所有等待线程,则可以使用 `notifyAll()` 方法:
```java
public class J5_NotifyAll {
private static final Object object = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (object) {
try {
System.out.println("对象object在线程1等待");
object.wait();
System.out.println("线程1后续操作");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
synchronized (object) {
try {
System.out.println("对象object在线程2等待");
object.wait();
System.out.println("线程2后续操作");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
synchronized (object) {
System.out.println("线程3开始操作");
System.out.println("对象object唤醒");
object.notifyAll();
}
}).start();
}
}
// 输出
对象object在线程1等待
对象object在线程2等待
线程3开始操作
对象object唤醒
线程2后续操作
线程1后续操作
```
在上面的示例中,由于有两个线程处于等待状态,所以 `notifyAll()` 的效果等价于调用 `notify()` 两次:
```java
object.notify();
object.notify();
```
### 7.2 条件变量 ### 7.2 条件变量
综上所述可以使用 `wait()``notify()` 配合内部锁 synchronized 来实现线程间的等待与唤醒,如果你使用的是显示锁而不是内部锁,此时可以使用 Condition 来实现同样的等待唤醒效果。Condition 接口中定义了如下方法:
+ await()
+ awaitUninterruptibly()
使用示例如下:
```java
public class AwaitAndSignal {
private static ReentrantLock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
static class IncreaseTask implements Runnable {
@Override
public void run() {
try {
lock.lock();
String threadName = Thread.currentThread().getName();
System.out.println(threadName + "线程等待通知...");
condition.await();
System.out.println(threadName + "线程后续操作");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new IncreaseTask());
thread1.start();
Thread.sleep(1000);
System.out.println("主线程开始操作");
lock.lock();
System.out.println("主线程唤醒");
condition.signal();
lock.unlock();
}
}
// 输出:
Thread-0线程等待通知...
主线程开始操作
主线程唤醒
Thread-0线程后续操作
```
### 7.3 CountDownLatch ### 7.3 CountDownLatch
### 7.4 CyclicBarrier ### 7.4 CyclicBarrier