JAVA线程间协作wait、notify、notifyAll、sleep用途

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shuaipu813/article/details/54017578

在上节中,介绍了java多线程中同步锁的概念,synchronized方法和synchronized代码块都是为了解决线程并发的问题,同一时间允许一个线程访问当前类或者对象。如果涉及到线程间的协作通信,就需要用到wait、notify、notifyAll方法,这三个方法是Object的方法。也就是任何对象都具有这三个方法,在java中wait、notify、notifyAll要放在synchronized方法中或者synchronized代码块中使用。从功能上来说,wait方法在线程获得对象锁之后,主动释放掉对象锁,并且休眠当前线程。直到有线程调用notify方法之后,他才会继续获得对象锁执行当前线程。notify方法就是用来唤醒对象锁的,但是notify执行完之后并不是马上执行当前唤醒的线程,而是等当前线程正在执行的线程执行完之后再执行。wait方法和Thread的Sleep方法作用类似,都是暂停线程,释放cpu使用权。区别在于wait方法会释放掉锁,而sleep只是休眠当前对象,并不会让出对象锁。调用了wait的线程会一直等待,后面代码不会再执行,直到有其他线程调用notify或者notifyAll才会继续执行。notifyAll的作用是唤醒所有的休眠的线程,注意只是唤醒被wait的线程。实例如下:

package com.thread.test;
public class MainTestThread {
	public static void main(String[] aa) {
		final MainTestThread test = new MainTestThread();
		//创建线程1
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					test.test1("线程1");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
		//创建线程2
		Thread thread1 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					test.test1("线程2");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
		//创建线程3
		Thread thread2 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					test.test1("线程3");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
		//启动线程
		thread.start();
		thread1.start();
		thread2.start();
	}

	public void test1(String thread) throws InterruptedException {
		synchronized (this) {
			for (int j = 1; j <= 5; j++) {
				//当为1的时候,表示进来新线程
				if (j == 1) {
					System.out.println(thread + "进入");
				}
				//为3的时候,暂时当前线程,并且释放对象锁
				if (j == 3) {
					this.wait();
				}
				System.out.println(thread + "第" + j + "运行");
				//唤醒该线程
				this.notify();
			}
		}
	}
}
运行结果如下:



但是也有出现这种情况:


最后一个线程执行了一半,这是因为notify在唤醒休眠线程的时候,是随机唤醒的。当线程1执行到3时,wait后,另一个线程进入,并且唤醒线程1。然后又执行线程1(线程的执行是无顺序的,不会因为你先调用就先执行某个线程),那么最后一个线程执行到3的时候,被休眠了。没有其他的线程来唤醒,一直等待下去。使用sleep来休眠当前执行线程:

package com.thread.test;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainTestThread3 {
	public static void main(String[] aa){
		final MainTestThread3 test=new MainTestThread3();
		 Thread thread=new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					test.test1("线程1");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
		 Thread thread1=new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					test.test1("线程2");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
		 Thread thread2=new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						test.test1("线程3");
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
		thread.start();
		thread1.start();
		thread2.start();
	}
	
	public void test1(String thread) throws InterruptedException{
		SimpleDateFormat sim=new SimpleDateFormat("yyyyMMddHHmmssSS");
		synchronized (this) {
			for (int j = 1; j <= 5; j++) {
				if(j==1){
					System.out.println(thread+"进入");
				}
				if(j==3){
					String data1=sim.format(new Date());
					Thread.sleep(3000);
					String data2=sim.format(new Date());
					System.out.println("执行花费了:"+String.valueOf((Long.parseLong(data2)-Long.parseLong(data1))+"毫秒"));
				}
				System.out.println(thread+"第"+j+"运行");
			}
		}
	}
}
执行结果:



猜你喜欢

转载自blog.csdn.net/shuaipu813/article/details/54017578