线程通信、notify和notifyAll、死锁

一、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再次消费,没有数据,释放锁,进入等待。
好了,四个线程都在等。。。没有人来唤醒,死锁!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值