Java中对应等待和通知的方法:wait、notify

一、wait方法

(1)方法wait()的作用是使当前执行代码的线程进行等待,该方法会将该线程放入”预执行队列“中,并且在wait()所在的代码处停止执行,直到接到通知或被中断为止。
(2)在调用wait()之前,线程必须获得该对象级别锁,这是一个很重要的地方,很多时候我们可能会忘记这一点,即只能在同步方法或同步块中调用wait()方法。
(3)还需要注意的是wait()是释放锁的,即在执行到wait()方法之后,当前线程会释放锁,当从wait()方法返回前,线程与其他线程竞争重新获得锁。

二、notify方法

(1)和wait()方法一样,notify()方法也要在同步块或同步方法中调用,即在调用前,线程也必须获得该对象的对象级别锁。
(2)该方法是用来通知那些可能等待该对象的对象锁的其他线程,如果有多个线程等待,则由线程规划器随机挑选出其中一个呈wait状态的线程,对其发出通知notify,并使它等待获取该对象的对象锁。
(3)这里需要注意的是,执行notify方法之后,当前线程不会立即释放其拥有的该对象锁,而是执行完之后才会释放该对象锁,被通知的线程也不会立即获得对象锁,而是等待notify方法执行完之后,释放了该对象锁,才可以获得该对象锁。
(4)notifyAll()通知所有等待同一共享资源的全部线程从等待状态退出,进入可运行状态,重新竞争获得对象锁。

三、wait()/notify()方法总结

(1)wait()/notify()要集合synchronized关键字一起使用,因为他们都需要首先获取该对象的对象锁;
(2)wait方法是释放锁,notify方法是不释放锁的;

四、注意事项

(1)wait()和notify()方法要在同步块或同步方法中调用,即在调用前,线程也必须获得该对象的对象级别锁。
(2)wait方法是释放锁,notify方法是不释放锁的;
(3)notify每次唤醒wait等待状态的线程都是随机的,且每次只唤醒一个;
(4)notifAll每次唤醒wait等待状态的线程使之重新竞争获取对象锁,优先级最高的那个线程会最先执行;
(5)当线程处于wait()状态时,调用线程对象的interrupt()方法会出现InterruptedException异常;

五、线程间的通信方式

(1)锁机制 
1.1 互斥锁:提供了以排它方式阻止数据结构被并发修改的方法。 
1.2 读写锁:允许多个线程同时读共享数据,而对写操作互斥。 
1.3 条件变量:可以以原子的方式阻塞进程,直到某个特定条件为真为止。

对条件测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
(2)信号量机制:包括无名线程信号量与有名线程信号量 
(3)信号机制:类似于进程间的信号处理。

线程间通信的主要目的是用于线程同步,所以线程没有象进程通信中用于数据交换的通信机制。

demo:

package thread.demo04.test2;

import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;

public class MyQueue {

	// 1、需要一个承装元素的集合
	private final LinkedList<Object> list = new LinkedList<>();
	// 2、需要一个计数器
	private final AtomicInteger count = new AtomicInteger(0);
	// 3、需要指定上限和下限
	private final int maxSize = 5;
	private final int minSize = 0;

	// 5、初始化锁对象
	private final Object lock = new Object();

	/**
	 * put方法
	 */
	public void put(Object obj) {
		synchronized (lock) {
			// 达到最大无法添加,进入等到
			while (count.get() == maxSize) {
				try {
					lock.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			list.add(obj); // 加入元素
			count.getAndIncrement(); // 计数器增加
			System.out.println(" 元素 " + obj + " 被添加 ");
			lock.notify(); // 通知另外一个阻塞的线程方法
		}
	}

	/**
	 * get方法
	 */
	public Object get() {
		Object temp;
		synchronized (lock) {
			// 达到最小,没有元素无法消费,进入等到
			while (count.get() == minSize) {
				try {
					lock.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			count.getAndDecrement();
			temp = list.removeFirst();
			System.out.println(" 元素 " + temp + " 被消费 ");
			lock.notify();
		}
		return temp;
	}

	public int size() {
		return count.get();
	}

}


package thread.demo04.test2;

public class Test {
	public static void main(String[] args) throws Exception {

		final MyQueue myQueue = new MyQueue();
		initMyQueue(myQueue);

		Thread t1 = new Thread(() -> {
			myQueue.put("f");
			myQueue.put("g");
			myQueue.put("h");
			myQueue.put("i");
		}, "t1");

		Thread t2 = new Thread(() -> {
			try {
				Thread.sleep(1000);
				myQueue.get();
				Thread.sleep(1000);
				myQueue.get();
				Thread.sleep(1000);
				myQueue.get();
				Thread.sleep(1000);
				myQueue.get();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}, "t2");

		t1.start();
		Thread.sleep(1000);
		t2.start();

	}

	private static void initMyQueue(MyQueue myQueue) {
		myQueue.put("a");
		myQueue.put("b");
		myQueue.put("c");
		myQueue.put("d");
		myQueue.put("e");
		System.out.println("当前元素个数:" + myQueue.size());
	}
}

猜你喜欢

转载自my.oschina.net/mengzhang6/blog/1824228