我的java之路(一):锁定、等待和通知——要操作同一对象

最近在听java的课,老师的PPT上有一个线程同步的例子,是要利用synchronized、wait和notify来实现。我把它输入到电脑并且补全了所有罗杰。运行之后发现它没有按照预想的输出结果。琢磨了好久之后,才找到法门。

代码如下:

一个栈的模拟:

View Code
package ThreadDemo;

import java.util.*;

public class StackDemo {
    private Vector buffer = new Vector(400, 200);
    public synchronized char pop()
    {
        char c;
        
        while(buffer.size() == 0)
        {
            try
            {
                this.wait();
            }
            catch(InterruptedException e){}
        }
        
        Object top = buffer.remove(buffer.size() - 1);
        c = (Character)top;
        
        return c;
    }
    
    public synchronized void push(char c)
    {
        this.notify();
        Character charObj = new Character(c);
        buffer.addElement(charObj);
    }
}

两个线程:

View Code
package ThreadDemo;

public class ThreadPush implements Runnable {
    
    StackDemo stack = new StackDemo();    
    public void run()
    {
        char c;
        for(int i=0; i < 200; i++)
        {
            c = (char)(Math.random()*26 + 'A');
            stack.push(c);
            try
            {
                Thread.sleep(300);
            }
            catch(InterruptedException e){}
        }
    }
}

和:

View Code
package ThreadDemo;

import java.util.*;

public class ThreadPop implements Runnable {
    
    StackDemo stack = new StackDemo();    
    public void run()
    {
        char c;
        for(int i = 0; i < 200; i ++)
        {
            c = stack.pop();
            System.out.println(c);
            
            try
            {
                Thread.sleep(300);
            }
            catch(InterruptedException e){}
        }
    }
}

主函数:

View Code
package ThreadDemo;
public class ThreadDemoMain {
        public static void main(String[] args) {            
        ThreadPush pushObject = new ThreadPush();
        Thread thread1 = new Thread(pushObject);
        thread1.start();
        
        ThreadPop popObject = new ThreadPop();
        Thread thread2 = new Thread(popObject);
        thread2.start();
    }
}

执行的情况是:pop线程一旦wait就再也醒不来了;push线程倒是一直在正常工作。这我就很纳闷,push进去那么多,而且notify语句也执行了,pop线程始终跟喝醉了似的,没有任何反应。无奈之下,我把PPT又翻出来,重新看wait的用法。发现它说,x.wait()之后,线程就进入了x对象的等待池。我的程序里边用的是,this.wait,this是谁?不就是StackDemo的实例嘛?。。。哦,我明白了,两个线程使用了两个不相同的StackDemo实例。这。。。

修改之后的代码:

栈模拟的代码没变。。。

两个线程:(在构造函数中要求传入StackDemo的实例,而不是自己生成!!!)

View Code
package ThreadDemo;

public class ThreadPush implements Runnable {
    
    StackDemo stack = null;
    
    public ThreadPush(StackDemo stack)
    {
        this.stack = stack;
    }
    
    public ThreadPush(){}
    
    public void run()
    {
        char c;
        for(int i=0; i < 200; i++)
        {
            c = (char)(Math.random()*26 + 'A');
            stack.push(c);
            try
            {
                Thread.sleep(300);
            }
            catch(InterruptedException e){}
        }
    }
}

和:

View Code
package ThreadDemo;

import java.util.*;

public class ThreadPop implements Runnable {
    
    StackDemo stack = null;
    
    public ThreadPop(StackDemo stack)
    {
        this.stack = stack;
    }
    public ThreadPop(){}
    
    public void run()
    {
        char c;
        for(int i = 0; i < 200; i ++)
        {
            c = stack.pop();
            System.out.println(c);
            
            try
            {
                Thread.sleep(300);
            }
            catch(InterruptedException e){}
        }
    }
}

主函数:(创建一个StackDemo实例,并且传入两个线程!!!)

View Code
package ThreadDemo;

public class ThreadDemoMain {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        StackDemo stack = new StackDemo();
        
        ThreadPush pushObject = new ThreadPush(stack);
        Thread thread1 = new Thread(pushObject);
        thread1.start();
        
        ThreadPop popObject = new ThreadPop(stack);
        Thread thread2 = new Thread(popObject);
        thread2.start();
    }
}

嗒嗒,程序终于正常工作了,乖乖地push进去200个字符,并且在pop之后输出。

这个故事告诉我们,上锁啊,等待啊,通知啊,都要对相同的对象才行。否则,就会出现我遇到的情况,一个按规定发通知,另一个死等,啥也没等到。

原文地址:https://www.cnblogs.com/ceachy/p/2549259.html