[零基础学JAVA]Java SE应用部分-26.多线程(04)

生产者和消费者问题(1)
[零基础学JAVA]Java SE应用部分-26.多线程(04)
生产者和消费者问题(2)
[零基础学JAVA]Java SE应用部分-26.多线程(04)
class Person{    
        String name = "张三";    
        String sex = "男";    
        // 张三 --> 男    
        // 李四 --> 女    
}    
class Pro implements Runnable{    
        //声明一个共享区域    
        Person per = null;    
        public Pro(Person p){    
                this.per = p;    
        }    
        public void run(){    
                int i = 0;    
                while(true){    
                        if (i==0){    
                                per.name = "李四";    
                                per.sex = "女";    
                                i=1;    
                        }else{    
                                per.name = "张三";    
                                per.sex = "男";    
                                i =0;    
                        }    
                }    
        }    
}    
class Cus implements Runnable{    
        Person per = null;    
        public Cus(Person p){    
                this.per = p;    
        }    
        public void run(){    
                while(true){    
                        System.out.println(per.name+" --> "+per.sex);    
                }    
        }    
}    
public class ThreadDemo01{    
        public static void main(String args[]){    
                Person per = new Person();    
                Pro p = new Pro(per);    
                Cus c = new Cus(per);    
                new Thread(p).start();    
                new Thread(c).start();    
        }    
}
看下效果:
[零基础学JAVA]Java SE应用部分-26.多线程(04)
以上代码已经可以从输出中看见了一些错误了,所以此处我们可以将代码进行修改,加入一些延迟,这样错误比较明显了
class Person{    
        String name = "张三";    
        String sex = "男";    
        // 张三 --> 男    
        // 李四 --> 女    
}    
class Pro implements Runnable{    
        //声明一个共享区域    
        Person per = null;    
        public Pro(Person p){    
                this.per = p;    
        }    
        public void run(){    
                int i = 0;    
                while(true){    
                        if (i==0){    
                                per.name = "李四";    
                                try{    
                                        Thread.sleep(100);    
                                }catch (Exception e){}    
                                per.sex = "女";    
                                i=1;    
                        }else{    
                                per.name = "张三";    
                                per.sex = "男";    
                                i =0;    
                        }    
                }    
        }    
}    
class Cus implements Runnable{    
        Person per = null;    
        public Cus(Person p){    
                this.per = p;    
        }    
        public void run(){    
                while(true){    
                        try{    
                                        Thread.sleep(100);    
                                }catch (Exception e){}    
                        System.out.println(per.name+" --> "+per.sex);    
                }    
        }    
}    
public class ThreadDemo02{    
        public static void main(String args[]){    
                Person per = new Person();    
                Pro p = new Pro(per);    
                Cus c = new Cus(per);    
                new Thread(p).start();    
                new Thread(c).start();    
        }    
}
[零基础学JAVA]Java SE应用部分-26.多线程(04)
之前的两个问题已经全部出现了,现在解决第一个:关于设置内容的问题; 
· 永远要保持张三是男,李四是女。
class Person{    
        private String name = "张三";    
        private String sex = "男";    
        // 张三 --> 男    
        // 李四 --> 女    
        public synchronized void set(String name,String sex){    
                this.name = name;    
                // 加入延迟验证设置是否生效    
                try{    
                        Thread.sleep(100);    
                }catch (Exception e){}    
                this.sex = sex;    
        }    
        //设置一个输出方法    
        public synchronized void get(){    
                try{    
                        Thread.sleep(100);    
                }catch (Exception e){}    
                System.out.println(this.name+" --> "+this.sex);    
        }    
}    
class Pro implements Runnable{    
        //声明一个共享区域    
        Person per = null;    
        public Pro(Person p){    
                this.per = p;    
        }    
        public void run(){    
                int i = 0;    
                while(true){    
                        if (i==0){    
                                per.set("李四","女");    
                                i=1;    
                        }else{    
                                per.set("张三","男");    
                                i =0;    
                        }    
                }    
        }    
}    
class Cus implements Runnable{    
        Person per = null;    
        public Cus(Person p){    
                this.per = p;    
        }    
        public void run(){    
                while(true){    
                        per.get();    
                }    
        }    
}    
public class ThreadDemo03{    
        public static void main(String args[]){    
                Person per = new Person();    
                Pro p = new Pro(per);    
                Cus c = new Cus(per);    
                new Thread(p).start();    
                new Thread(c).start();    
        }    
}
[零基础学JAVA]Java SE应用部分-26.多线程(04)
通过同步方法,确实解决了设置上的问题,张三是男的,李四是女的,但是第二个问题还没有解决,以上效果看到得只是假像,如果休眠时间设置都取消的话可以看出问题哈~
class Person{    
        private String name = "张三";    
        private String sex = "男";    
        // 张三 --> 男    
        // 李四 --> 女    
        public synchronized void set(String name,String sex){    
                this.name = name;    
                // 加入延迟验证设置是否生效    
                this.sex = sex;    
        }    
        //设置一个输出方法    
        public synchronized void get(){    
                System.out.println(this.name+" --> "+this.sex);    
        }    
}    
class Pro implements Runnable{    
        //声明一个共享区域    
        Person per = null;    
        public Pro(Person p){    
                this.per = p;    
        }    
        public void run(){    
                int i = 0;    
                while(true){    
                        if (i==0){    
                                per.set("李四","女");    
                                i=1;    
                        }else{    
                                per.set("张三","男");    
                                i =0;    
                        }    
                }    
        }    
}    
class Cus implements Runnable{    
        Person per = null;    
        public Cus(Person p){    
                this.per = p;    
        }    
        public void run(){    
                while(true){    
                        per.get();    
                }    
        }    
}    
public class ThreadDemo04{    
        public static void main(String args[]){    
                Person per = new Person();    
                Pro p = new Pro(per);    
                Cus c = new Cus(per);    
                new Thread(p).start();    
                new Thread(c).start();    
        }    
}
[零基础学JAVA]Java SE应用部分-26.多线程(04)
如果设置成只有一个休眠中断的话看得明显
class Person{    
        private String name = "张三";    
        private String sex = "男";    
        // 张三 --> 男    
        // 李四 --> 女    
        public synchronized void set(String name,String sex){    
                this.name = name;    
                // 加入延迟验证设置是否生效    
                this.sex = sex;    
        }    
        //设置一个输出方法    
        public synchronized void get(){    
                System.out.println(this.name+" --> "+this.sex);    
        }    
}    
class Pro implements Runnable{    
        //声明一个共享区域    
        Person per = null;    
        public Pro(Person p){    
                this.per = p;    
        }    
        public void run(){    
                int i = 0;    
                while(true){    
                        if (i==0){    
                                per.set("李四","女");    
                                i=1;    
                        }else{    
                                per.set("张三","男");    
                                i =0;    
                        }    
                }    
        }    
}    
class Cus implements Runnable{    
        Person per = null;    
        public Cus(Person p){    
                this.per = p;    
        }    
        public void run(){    
                while(true){    
                        try    
                        {    
                                Thread.sleep(500);    
                        }    
                        catch (Exception e)    
                        {    
                        }    
                        per.get();    
                }    
        }    
}    
public class ThreadDemo04{    
        public static void main(String args[]){    
                Person per = new Person();    
                Pro p = new Pro(per);    
                Cus c = new Cus(per);    
                new Thread(p).start();    
                new Thread(c).start();    
        }    
}
[零基础学JAVA]Java SE应用部分-26.多线程(04)
如果不让其重复取值,我们可以学习下下面的知识
绿灯可以放数据,不能取数据
[零基础学JAVA]Java SE应用部分-26.多线程(04)
红灯可以取数据,不能放数据
[零基础学JAVA]Java SE应用部分-26.多线程(04)
同理依次执行哈~
[零基础学JAVA]Java SE应用部分-26.多线程(04)
如果红灯时,即消费者(read)取数据时,CPU将资源给了生产者,当生产者将数据要放入时,发现是红灯,只能等待哈~
[零基础学JAVA]Java SE应用部分-26.多线程(04)
等到绿灯时生产者才能将cccc数据放入哈~
[零基础学JAVA]Java SE应用部分-26.多线程(04)
这样的机制就是线程的等待和唤醒,也就是下面的内容哈~
线程的等待及唤醒
[零基础学JAVA]Java SE应用部分-26.多线程(04)
当发现消费者没有取走内容的时候,生产者应该等待 
当消费者把内容取走之后,生产者才可以放。
class Person{    
        private String name = "张三";    
        private String sex = "男";    
        private boolean flag = false;    
        // flag = true时表示允许生产但不允许取走    
        // flag = false时表示允许取走但不允许生产    
        // 张三 --> 男    
        // 李四 --> 女    
        //编写一个设置内容的方法    
        public synchronized void set(String name,String sex){    
                //如果flag的值不是true则要等待    
                if (!flag){    
                        //等待    
                        try{    
                                wait();    
                        }catch(Exception e){}    
                }    
                try{    
                        Thread.sleep(100);    
                }catch (Exception e){}    
                // 如果向下继续执行了,则表示可以设置,flag = true    
                this.name = name;    
                this.sex = sex;    
                // 修改设置的标志    
                flag = false;    
                //唤醒其他线程    
                notify();    
        }    
        //设置一个输出方法    
        public synchronized void get(){    
                // 如果flag的值为true的时候,表示要等待    
                if(flag){    
                        try{    
                                wait();    
                        }catch(Exception e){}    
                }    
                try{    
                        Thread.sleep(100);    
                }catch (Exception e){}    
                //如果向下执行了,则表示允许取出    
                System.out.println(this.name+" --> "+this.sex);    
                //改变标志,表示可以生产了    
                flag = true;    
                notify();    
        }    
}    
class Pro implements Runnable{    
        //声明一个共享区域    
        Person per = null;    
        public Pro(Person p){    
                this.per = p;    
        }    
        public void run(){    
                int i = 0;    
                while(true){    
                        if (i==0){    
                                per.set("李四","女");    
                                i=1;    
                        }else{    
                                per.set("张三","男");    
                                i =0;    
                        }    
                }    
        }    
}    
class Cus implements Runnable{    
        Person per = null;    
        public Cus(Person p){    
                this.per = p;    
        }    
        public void run(){    
                while(true){    
                        per.get();    
                }    
        }    
}    
public class ThreadDemo05{    
        public static void main(String args[]){    
                Person per = new Person();    
                Pro p = new Pro(per);    
                Cus c = new Cus(per);    
                new Thread(p).start();    
                new Thread(c).start();    
        }    


看下效果:这样就解决了第二个问题
[零基础学JAVA]Java SE应用部分-26.多线程(04) 
以上的三个方法,实际上是Object类中的三个方法。
[零基础学JAVA]Java SE应用部分-26.多线程(04)
控制线程的生命周期
[零基础学JAVA]Java SE应用部分-26.多线程(04)
[零基础学JAVA]Java SE应用部分-26.多线程(04)
以上的很多方法都不建议继续使用了,因为会造成死锁,那么如果我现在要停止一个线程的运行,该怎么办? 
C盘拷贝内容到D盘,中止拷贝时系统会有些延迟,同理我们可以通过设置标志位让其停止。
class MyThread implements Runnable{    
        private boolean flag = true;    
        public void run(){    
                int i=0;    
                while(flag){    
                        System.out.println(Thread.currentThread().getName()+" --> 运行,i ="+(i++));    
                }    
        }    
        public void setFlag(boolean flag){    
                this.flag = flag;    
        }    
}    
public class ThreadDemo06{    
        public static void main(String args[]){    
                MyThread mt = new MyThread();    
                new Thread(mt).start();    
                try{    
                        Thread.sleep(300);    
                }catch(Exception e){}                 
                //将线程的运行的条件修改了,则肯定停止运行    
                mt.setFlag(false);    
        }    
}
或者也可以修改成throws Exception
class MyThread implements Runnable{    
        private boolean flag = true;    
        public void run(){    
                int i=0;    
                while(flag){    
                        System.out.println(Thread.currentThread().getName()+" --> 运行,i ="+(i++));    
                }    
        }    
        public void setFlag(boolean flag){    
                this.flag = flag;    
        }    
}    
public class ThreadDemo06{    
        public static void main(String args[])throws Exception{    
                MyThread mt = new MyThread();    
                new Thread(mt).start();    
                Thread.sleep(300);    
                //将线程的运行的条件修改了,则肯定停止运行    
                mt.setFlag(false);    
        }    
}
发现程序运行一段时间后自己停止运行了哈~~~
[零基础学JAVA]Java SE应用部分-26.多线程(04)
多线程面试题:
 [零基础学JAVA]Java SE应用部分-26.多线程(04)
可以直接参考生产者和消费者问题。
class Num{    
        int j = 0;    
}    
class Inc implements Runnable{    
        private Num n = null;    
        public Inc(Num n){    
                this.n = n;    
        }    
        public void run(){    
                while(true){    
                        System.out.println("加:"+Thread.currentThread().getName()+" -->"+n.j++);    
                }    
        }    
}    
class Dec implements Runnable{    
        private Num n = null;    
        public Dec(Num n){    
                this.n = n;    
        }    
        public void run(){    
                while(true){    
                        System.out.println("减:"+Thread.currentThread().getName()+" -->"+n.j--);    
                }    
        }    
}    
public class ThreadDemo07{    
        public static void main(String args[]){    
                Num n = new Num();    
                Inc i = new Inc(n);    
                Dec d = new Dec(n);    
                new Thread(i,"加线程A:").start();    
                new Thread(i,"加线程B:").start();    
                new Thread(d,"减线程C:").start();    
                new Thread(d,"减线程D:").start();    
        }    
}
看下效果:
[零基础学JAVA]Java SE应用部分-26.多线程(04)
 [零基础学JAVA]Java SE应用部分-26.多线程(04)
本季重点:
[零基础学JAVA]Java SE应用部分-26.多线程(04)
使用Runnable可以实现资源的共享,但是实现之后就必须想办法对资源进行同步,否则会出现数据不正确的情况,但是如果过多的使用了同步,则会发生死锁。
完整的方法定义: 
[public|protected|default|private] [synchronized] [static] [final] 
返回值类型|void 方法名称(参数列表) [throws 异常]
#############################################################









本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/p12,如需转载请自行联系原作者