之所以会写这篇博客,完全是因为博主一直以来对这两个函数的理解有所模糊,于是在网上查阅资料,捋顺了一些东西,在拿出来分享的同时也希望大家能对我有所指正。
一、首先上代码,这段代码是关于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能控制线程执行顺序的原因所在。