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

本文通过实例详细解析生产者和消费者问题,展示了如何利用同步方法和线程的等待唤醒机制来确保数据的一致性和完整性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

生产者和消费者问题(1)
image
生产者和消费者问题(2)
image
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();    
        }    
}
看下效果:
image
以上代码已经可以从输出中看见了一些错误了,所以此处我们可以将代码进行修改,加入一些延迟,这样错误比较明显了
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();    
        }    
}
image
之前的两个问题已经全部出现了,现在解决第一个:关于设置内容的问题;
· 永远要保持张三是男,李四是女。
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();    
        }    
}
image
通过同步方法,确实解决了设置上的问题,张三是男的,李四是女的,但是第二个问题还没有解决,以上效果看到得只是假像,如果休眠时间设置都取消的话可以看出问题哈~
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();    
        }    
}
image
如果设置成只有一个休眠中断的话看得明显
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();    
        }    
}
image
如果不让其重复取值,我们可以学习下下面的知识
绿灯可以放数据,不能取数据
image
红灯可以取数据,不能放数据
image
同理依次执行哈~
image
如果红灯时,即消费者(read)取数据时,CPU将资源给了生产者,当生产者将数据要放入时,发现是红灯,只能等待哈~
image
等到绿灯时生产者才能将cccc数据放入哈~
image
这样的机制就是线程的等待和唤醒,也就是下面的内容哈~
线程的等待及唤醒
image
当发现消费者没有取走内容的时候,生产者应该等待
当消费者把内容取走之后,生产者才可以放。
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();    
        }    
}

看下效果:这样就解决了第二个问题
image 
以上的三个方法,实际上是Object类中的三个方法。
image
控制线程的生命周期
image
image
以上的很多方法都不建议继续使用了,因为会造成死锁,那么如果我现在要停止一个线程的运行,该怎么办?
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);    
        }    
}
发现程序运行一段时间后自己停止运行了哈~~~
image
多线程面试题:
  image
可以直接参考生产者和消费者问题。
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();    
        }    
}
看下效果:
image
  image
本季重点:
image
使用Runnable可以实现资源的共享,但是实现之后就必须想办法对资源进行同步,否则会出现数据不正确的情况,但是如果过多的使用了同步,则会发生死锁。
完整的方法定义:
[public|protected|default|private] [synchronized] [static] [final]
返回值类型|void 方法名称(参数列表) [throws 异常]
#############################################################
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值