一、while(true)轮询
public class ListAdd1 {
private volatile static List list = new ArrayList();
public void add(){
list.add("jack");
}
public int size(){
return list.size();
}
public static void main(String[] args) {
final ListAdd1 list1 = new ListAdd1();
//创建t1线程,往list1中加10个字符串,每次休眠500ms
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
for(int i = 0; i < 10; i++){
list1.add();
System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
//t2线程: 当list1中有5个元素时,打印一句话,抛出异常
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
//轮询,不断的判断size的值
while(true){
if(list1.size() == 5){
System.out.println("当前线程收到通知:" + Thread.currentThread().getName() + " list size = 5 t2线程停止..");
throw new RuntimeException();
}
}
}
}, "t2");
t1.start();
t2.start();
}
}
执行结果
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程收到通知:t2 list size = 5 t2线程停止..
Exception in thread "t2" java.lang.RuntimeException
at com.liaoxiang.multithreading3.base.线程通信.ListAdd1$2.run(ListAdd1.java:44)
at java.lang.Thread.run(Thread.java:748)
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
二、wait()和notify()
public class ListAdd2 {
private volatile static List list = new ArrayList();
public void add(){
list.add("jack");
}
public int size(){
return list.size();
}
public static void main(String[] args) {
final ListAdd2 list2 = new ListAdd2();
final Object lock = new Object();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
synchronized (lock) {
System.out.println("t1启动..");
for(int i = 0; i <10; i++){
list2.add();
System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
Thread.sleep(500);
if(list2.size() == 5){
System.out.println("已经发出通知..");
//size=5的时候唤醒等待的线程,但是并没有释放锁,当t1线程,即10次循环执行完之后才会释放锁
lock.notify();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
/**
* 先启动t2线程,拿到锁,此时size不为5,又释放锁,处于等待状态
* 执行t1线程,当size=5时,唤醒当前线程,退出wait状态,但是t1还没有执行完,没释放锁,所以要等10次循环完成才能执行t2
*/
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
System.out.println("t2启动..");
if(list2.size() != 5){
try {
lock.wait();//size不等于5,t2释放锁,等待,t1执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");
throw new RuntimeException();
}
}
}, "t2");
t2.start();
t1.start();
}
}
执行结果:
t2启动..
t1启动..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
已经发出通知..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t2收到通知线程停止..
Exception in thread "t2" java.lang.RuntimeException
at com.liaoxiang.multithreading3.base.线程通信.ListAdd2$2.run(ListAdd2.java:65)
at java.lang.Thread.run(Thread.java:748)
两个线程交替执行
class PrintNum implements Runnable {
int num = 1;
//Object obj = new Object();
public void run() {
while (true) synchronized (this) {
notify();
if (num <= 100) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ": " + num);
num++;
} else {
break;
}
// 执行一次就wait(), 释放锁,另一个线程就过来拿到锁,执行上面的程序,直到wait()
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class TestCommunication {
public static void main(String[] args) {
PrintNum p = new PrintNum();
Thread t1 = new Thread(p);
Thread t2 = new Thread(p);
t1.setName("甲");
t2.setName("乙");
t1.start();
t2.start();
}
}
甲: 1
乙: 2
甲: 3
乙: 4
甲: 5
乙: 6
甲: 7
乙: 8
甲: 9
乙: 10
notify() 和 notifyAll()之间的区别
我们可以利用wait()来让一个线程在某些条件下暂停运行。例如,在生产者消费者模型中,生产者线程在缓冲区为满的时候,消费者在缓冲区为空的时候,都应该暂停运行。如果某些线程在等待某些条件触发,那当那些条件为真时,可以用 notify 和 notifyAll 来通知那些等待中的线程重新开始运行。不同之处在于,notify 仅仅通知一个线程,并且我们不知道哪个线程会收到通知,然而 notifyAll 会通知所有等待中的线程。换言之,如果只有一个线程在等待一个信号灯,notify和notifyAll都会通知到这个线程。但如果多个线程在等待这个信号灯,那么notify只会通知到其中一个,而其它线程并不会收到任何通知,而notifyAll会唤醒所有等待中的线程。
package com.liaoxiang.multithreading1.线程通信;
import java.util.ArrayList;
import java.util.List;
/**
* @auther Mr.Liao
* @date 2019/9/6 10:10
*/
public class NotifyAndNotifyAll {
private Buffer buffer = new Buffer();
public static void main(String[] args) {
NotifyAndNotifyAll nna = new NotifyAndNotifyAll();
Thread p1 = new Thread(new Runnable() {
int count = 4;
@Override
public void run() {
while (true) {
if (count > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
nna.produce();
count--;
} else break;
}
}
}, "生产者线程 1");
Thread p2 = new Thread(new Runnable() {
int count = 4;
@Override
public void run() {
while (true) {
if (count > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
nna.produce();
count--;
} else break;
}
}
}, "生产者线程 2");
Thread c1 = new Thread(new Runnable() {
int count = 4;
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count > 0) {
nna.consume();
count--;
} else break;
}
}
}, "消费者线程 1");
Thread c2 = new Thread(new Runnable() {
int count = 4;
@Override
public void run() {
while (true) {
if (count > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
nna.consume();
count--;
} else break;
}
}
}, "消费者线程 2");
p1.start();
p2.start();
c1.start();
c2.start();
}
public void produce() {
synchronized (this) {
while (buffer.isFull()) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
buffer.add();
notify();
}
}
public void consume() {
synchronized (this) {
while (buffer.isEmpty()) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
buffer.remove();
notify();
}
}
class Buffer {
private static final int MAX_CAPACITY = 1;
private ArrayList<Object> innerList = new ArrayList<>(MAX_CAPACITY);
public boolean isEmpty() {
//size=0 返回true
return innerList.isEmpty();
}
public boolean isFull() {
//添加一个元素就满,返回true
return innerList.size() == MAX_CAPACITY;
}
public void add() {
if (isFull()) {
throw new IndexOutOfBoundsException();
} else {
innerList.add(new Object());
}
System.out.println(Thread.currentThread().getName() + " add");
}
public void remove() {
if (isEmpty()) {
throw new IndexOutOfBoundsException();
} else {
innerList.remove(MAX_CAPACITY - 1);
}
System.out.println(Thread.currentThread().getName() + " remove");
}
}
}
死锁,程序不能正常执行
使用notifyAll正常执行
死锁过程分析:
c1拿到锁消费,没有数据,释放锁,进入等待。
c2拿到锁消费,没有数据,释放锁,进入等待。
p1拿到锁,第一次生产一个数据,唤醒,没有释放锁,第二次生产时,释放锁,进入等待。
如果p1唤醒的c1,p2和c1竞争锁,p2拿到锁,生产数据,发现是满的,释放锁,进入等待。
c1拿到锁,第一次消费一个数据,唤醒,第二次消费数据,释放锁,进入等待。
如果c1唤醒的是c2,则c2再次消费,没有数据,释放锁,进入等待。
好了,四个线程都在等。。。没有人来唤醒,死锁!