java学习历程:wait()与join()的理解误区

之所以会写这篇博客,完全是因为博主一直以来对这两个函数的理解有所模糊,于是在网上查阅资料,捋顺了一些东西,在拿出来分享的同时也希望大家能对我有所指正。

一、首先上代码,这段代码是关于wait()的使用。

package test;
class Person{
	private String Name;
	private int Age; 
	private boolean isEmpty = true;
	//表示共享资源对象是否为空,如果为 true,表示需要生产,如果为 false,则有数据了,不要生产
	public synchronized void push(String aName, int aAge){
		try {
			while(isEmpty == false){
				this.wait();//不写参数就是无限等
			}
			this.Name = aName;
			this.Age = aAge;
			Thread.sleep(10);
			
			isEmpty = false;
			this.notifyAll();//生产完毕,唤醒所有消费者
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	public synchronized void pop(){
		try {
			while(isEmpty == true){
				this.wait();
			}
			Thread.sleep(10);
			System.out.println(this.Name + " " + this.Age);

                        isEmpty = true;//设置 isEmpty为true,表示需要生产者生产对象
                        this.notifyAll();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
class Producer implements Runnable{
	Person p = null;
	
	public Producer(Person p){
		this.p = p;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i = 0;i<20;i++){
            if(i%2==0){
                p.push("Tom", 11);
            }else{
                p.push("Marry", 22);
            }			
		}
	}
}
class Consumer implements Runnable{
	Person p = null;
	
	public Consumer(Person p){
		this.p = p;
	}
	@Override
	public void run(){
		for(int i = 0; i<20; i++){
			this.p.pop();
		}
	}
}
public class ThreadTest2 {//写一个生产者消费者的演示程序
	public static void main(String[] args){
		Person p = new Person();
		Thread t1 = new Thread(new Producer(p));
		Thread t2 = new Thread(new Consumer(p));
		t1.start();
		t2.start();//总感觉线程的启动有顺序,而线程的运行没有
	}
}

这是一段简单的生产者与消费者的代码演示,生产一个person后消费一个person,出现Tom-11与Marry-22的交替显示,以证明确实是生产者与消费者的代码段,代码出处http://www.cnblogs.com/ysocean/p/6896219.html,文中发现在synchronized代码块中通过使用了wait()使得获得该对象的对象锁的线程进入对象的等待队列,直至唤醒(notifyAll())。

二、上代码,这段代码是关于join()的使用。

package test;

public class ThreadTest3 {
	class ThreadImp implements Runnable {
		public synchronized void run(){
			try{
				System.out.println(Thread.currentThread().getName() + "Begin");
				Thread.sleep(10);
				/*System.out.println(Thread.currentThread().getName() + "process");
				Thread.sleep(10);*/
				System.out.println(Thread.currentThread().getName() + "end");
				Thread.sleep(10);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	public static void main(String[] args)throws Exception{
		ThreadTest3 T3 = new ThreadTest3();
		ThreadImp th = T3.new ThreadImp();
		//子线程
		Thread t = new Thread(th,"线程1");
		Thread t2 = new Thread(th,"线程2");
		Thread t3 = new Thread(th,"线程3");
		Thread t4 = new Thread(th,"线程4");
		Thread t5 = new Thread(th,"线程5");
		t.start();
		t.join();
		t2.start();
		t2.join();
		t3.start();
		t3.join();
		t4.start();
		t4.join();
		t5.start();
		t5.join();
		System.out.println("the final");//main线程最后执行
		//t2.join();
		/*try{
			t.join(1000);//join的用法
			if (t.isAlive()) {
				System.out.println("线程1alive");
			} else {
				System.out.println("线程1dead");
			}
			System.out.println(Thread.currentThread().getName() + "finished");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}*/
	}
}

关于join()方法,其实可以看作wait(),JDK源码中的实现也是基于调用wait()方法的,有兴趣的可以自行研究一下,PS:Thread.join() 等同于Thread.wait(),无参数代表0,即无限等。上述代码通过调用join()实现了线程的有序执行。

三、关于这两个方法的个人理解

举个例子,现有两个线程A与B,A中调用了B.join(),那么A线程会停止,等B先运行完后A才开始运行。                                      那么有人会想当然的理解成,B.join()等同于B.wait(),不就是B在wait,也就是B等待吗,为什么反而会让A停运,让B先运行呢?这也是博主之前一直很模糊的地方。要理解这里,先假设一个对象D,需要知道其实wait()方法是D.wait(),也就是说获取了对象D的对象锁的线程释放该对象锁,重新进入对象的锁获取队列中,与其他线程一起竞争该锁,这也是为什么第一段代码中,对象Person进行wait后,需要notifyAll的原因,而第二段代码,需要把线程1、2、3、4、5看作是一个个对象,PS:java中很多东西都可以看作对象,线程当然不例外。主线程main看作是调用这些对象的线程,join()是一个synchronized方法,即在线程对象1、2、3、4、5被main线程调用了join后,main线程会释放该对象的对象锁,进入该对象的锁获取队列中,等待唤醒(例如该对象执行结束),这样main线程才能继续执行下去,这也是为什么join能控制线程执行顺序的原因所在。

你可能感兴趣的:(java)