zoukankan      html  css  js  c++  java
  • 我的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之后输出。

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

  • 相关阅读:
    USACO Grass Planting
    洛谷 P3178 [HAOI2015]树上操作
    史上最全NOIP初赛知识点
    史上最全的CSP-J/S 第一轮知识点
    洛谷 P1886 滑动窗口
    背包九讲—简单背包
    NOIP 2005 采药
    洛谷 P2357 守墓人
    NOI 2015 软件包管理器
    洛谷 P3384 【模板】树链剖分
  • 原文地址:https://www.cnblogs.com/ceachy/p/2549259.html
Copyright © 2011-2022 走看看