黑马程序员技术交流社区

标题: 多线程问题 [打印本页]

作者: NewDemo    时间: 2014-5-5 15:58
标题: 多线程问题
本帖最后由 NewDemo 于 2014-5-5 21:52 编辑
  1. public class ThreadTest2 {

  2.         /**
  3.          * @param args
  4.          * 生产者消费例子实现
  5.          * 思路:1.创建一个商品资源的类,并在其中定义两个加锁的方法用于模拟生产和消费的行为 2.定义生产者和消费者的类并实现Runnable接口
  6.          * 3.主函数中创建线程并关联资源。
  7.          */
  8.         public static void main(String[] args) {
  9.                 //创建线程并关联资源
  10.                 Resource r = new Resource();
  11.                 new Thread(new Producer(r)).start();
  12.                 new Thread(new Producer(r)).start();
  13.                 new Thread(new Producer(r)).start();
  14.                 new Thread(new Producer(r)).start();
  15.                 new Thread(new Consumer(r)).start();
  16.                 new Thread(new Consumer(r)).start();
  17. //                new Thread(new Consumer(r)).start();
  18. //                new Thread(new Consumer(r)).start();
  19.         }

  20. }
  21. //创建商品的类,公共资源
  22. class Resource{
  23.         private int count = 0;//用于记录商品的编号
  24.         private boolean flag = false;//定义标记用来控制线程的运行交替
  25.         //模拟生产行为
  26.         public synchronized void set(){
  27. while(flag)
  28.                         try {
  29.                                 this.wait();
  30.                         } catch (InterruptedException e) {
  31.                                 e.printStackTrace();
  32.                         }
  33.                 count++;
  34.                 flag = true;
  35.                 System.out.println(Thread.currentThread().getName()+"生产。。"+count);
  36.                 this.notifyAll();
  37.         }
  38.         //模拟消费行为
  39.         public synchronized void out(){
  40. while(!flag)
  41.                         try {
  42.                                 this.wait();
  43.                         } catch (InterruptedException e) {
  44.                                 e.printStackTrace();
  45.                         }
  46.                 flag = false;
  47.                 System.out.println(Thread.currentThread().getName()+"消费。。。。。"+count);
  48.                 this.notifyAll();
  49.         }
  50. }

  51. //生产者的类,实现接口,复写run方法
  52. class Producer implements Runnable{
  53.         private Resource r;
  54.         Producer(Resource r){
  55.                 this.r=r;
  56.         }
  57.         @Override
  58.         public void run() {
  59.                 while(true){
  60.                         r.set();
  61.                 }
  62.         }
  63. }
  64. //消费者的类,实现接口,复写run方法
  65. class Consumer implements Runnable{
  66.         private Resource r;
  67.         Consumer(Resource r){
  68.                 this.r=r;
  69.         }
  70.         @Override
  71.         public void run() {
  72.                 while(true){
  73.                         r.out();
  74.                 }
  75.         }
  76. }
复制代码
毕老师在讲课时用生产者t1,t2,消费者t3,t4解释了判断标记的时候为什么不能用if,但是我想问的是t1等待的时候不是还没有释放锁吗,那t2是如何拿到锁并也等待了呢?
看下wait方法的注释,当调用wait方法时就会释放锁,并且这个方法应该一直在循环中使用。



作者: 随风而去    时间: 2014-5-5 17:11
这个是我写的一个生产消费者示例 你可以研究下
  1. package test2;

  2. import java.util.ArrayList;
  3. import java.util.List;

  4. /**
  5. * 生成消费者模式
  6. * @author 李昂志
  7. *
  8. */
  9. public class ThreadRun {
  10.        
  11.         public static void main(String[] args) {
  12.                 new Thread(new Factory("福特")).start();   //两家汽车店
  13.                 new Thread(new Factory("宝马")).start();  
  14.                 new Thread(new Customer("马晓")).start();  //5个客户
  15.                 new Thread(new Customer("大米")).start();  
  16.                 new Thread(new Customer("小跳")).start();  
  17.                 new Thread(new Customer("Marry")).start();  
  18.                 new Thread(new Customer("Jack")).start();  

  19.         }
  20. }
  21. /**
  22. *生成者
  23. *生成汽车
  24. */
  25. class Factory  implements Runnable{
  26.         String name ;
  27.         public Factory(String name){
  28.                 this.name = name;
  29.         }

  30.         @Override
  31.         public void run() {
  32.                 // TODO Auto-generated method stub
  33.                 int i = 0 ;
  34.                 while(true){
  35.                         i++;
  36.                         try {
  37.                                 Thread.sleep(800); //每生产一辆汽车 休息0.8s
  38.                         } catch (InterruptedException e) {
  39.                                 // TODO Auto-generated catch block
  40.                                 e.printStackTrace();
  41.                         }
  42.                         //生产汽车
  43.                         Stores4S.getInstance().protect(name,i);
  44.                 }
  45.         }
  46. }
  47. /**
  48. * 汽车
  49. * @author 李昂志
  50. */
  51. class Car{
  52.         String name;
  53.         public Car(String name){
  54.                 this.name = name;
  55.         }
  56.         public String getName() {
  57.                 return name;
  58.         }
  59.         public void setName(String name) {
  60.                 this.name = name;
  61.         }
  62.         public Car() {
  63.         }
  64.        
  65. }
  66. /**
  67. * 消费者
  68. * 消费汽车
  69. */
  70. class Customer implements Runnable{
  71.         String name ;  //消费者的名字
  72.         private Car c ;
  73.         public Customer(String name){
  74.                 this.name = name;
  75.         }
  76.        
  77.         @Override
  78.         public void run() {
  79.                 while(true){
  80.                         if(c != null ) break;  //如果消费者已经买到车 则退出买车的方法
  81.                         try {
  82.                                 Thread.sleep(1000); //消费者每买辆车 休息1s
  83.                         } catch (InterruptedException e) {
  84.                                 // TODO Auto-generated catch block
  85.                                 e.printStackTrace();
  86.                         }
  87.                         c = Stores4S.getInstance().custom(name); //消费者买车
  88.                 }
  89.         }
  90.        
  91. }
  92. /**
  93. * 生产者用来卖东西
  94. * 消费这买东西的地方 先叫做门店吧
  95. * 一家4s汽车店  汽车店是唯一的
  96. * @author 李昂志
  97. */
  98. class Stores4S  {
  99.         private static Stores4S s = new Stores4S();
  100.         private static final int MAX = 5;
  101.         private List<Car> ls = new ArrayList<Car>();  //汽车店的容量
  102.         private Stores4S(){};
  103.         /**
  104.          * 饿汉单利模式 唯一  且线程安全
  105.          */
  106.         public static  Stores4S getInstance(){
  107.                 return s ;
  108.         }
  109.         /**
  110.          * 卖汽车
  111.          */
  112.         public synchronized Car custom(String name){
  113.                 while(ls.isEmpty()){
  114.                         try {
  115.                                 System.out.println("店里的汽车已销售完毕 请生产了再买 !");
  116.                                 wait();
  117.                         } catch (InterruptedException e) {
  118.                                 // TODO Auto-generated catch block
  119.                                 e.printStackTrace();
  120.                         }
  121.                 }
  122.                
  123.                 Car c = ls.get(ls.size()-1);System.out.println(name +" 买了一辆型号为:"+c.getName()+" 的汽车");
  124.                 ls.remove(c);
  125.                
  126.                
  127.                 notifyAll();
  128.                 return c;
  129.         }
  130.         /**
  131.          * 4s店 去汽车商拿货
  132.          * @param name
  133.          * @param i
  134.          */
  135.         public synchronized void protect(String name, int i){
  136.                 while(ls.size()>MAX){
  137.                         try {
  138.                                 System.out.println("店里的汽车已满 请消费了再生产 !");
  139.                                 wait();
  140.                         } catch (InterruptedException e) {
  141.                                 // TODO Auto-generated catch block
  142.                                 e.printStackTrace();
  143.                         }
  144.                 }
  145.                 ls.add(new Car(name+"_"+i));
  146.                 System.out.println(name +"汽车商 生产了一辆型号为: "+ls.get(ls.size()-1).getName()+" 的汽车");
  147.                 notifyAll();
  148.         }
  149. }
复制代码




作者: heima_xyu    时间: 2014-5-5 17:56
class Resource{
        private int count = 0;//用于记录商品的编号
        private boolean flag = false;//定义标记用来控制线程的运行交替
        //模拟生产行为
        public synchronized void set(){
if(flag)                                         //假设换成if, 假设       1.进入线程t1,因为flag为false   
try {                                                 //5.这时t2进来,也等待,然后执行消费行为的t3,t4
                                this.wait();             //4.因为flag为true,t1等待
                        } catch (InterruptedException e) {
                                e.printStackTrace();               //8.t1醒来,执行以下代码,在打印语句后,t2取得执行权,也打印了一次。
                        }                                                       //2.t1没有执行这段代码
                count++;                    
                flag = true;
                System.out.println(Thread.currentThread().getName()+"生产。。"+count);
                this.notifyAll();                                                    //3.flag变更为true,t1唤醒其他线程,但也可能继续循环,假设继续循环
        }


        //模拟消费行为
        public synchronized void out(){
if(!flag)                                         //6.t3进来,flag为!true,跳过try{}catch{}代码
                        try {
                                this.wait();
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                flag = false;                        
                System.out.println(Thread.currentThread().getName()+"消费。。。。。"+count);
                this.notifyAll();                      //7.flag变更为false, t3唤醒其他线程,假设是t1和t2取得CPU使用权
        }
}

//1--8的步骤即线程不安全的原因所在,其实即使是while,该程序还是有微小的可能出错,notifyAll不如Lock系统的Condition的某个对象调用sig
nal()方法


作者: NewDemo    时间: 2014-5-5 18:03
heima_xyu 发表于 2014-5-5 17:56
class Resource{
        private int count = 0;//用于记录商品的编号
        private boolean flag = fa ...

你说的这个毕老师在视频里讲到了,我想问的是t1等待的时候不是还没有释放锁吗,那t2是如何拿到锁并也等待了呢?

作者: heima_xyu    时间: 2014-5-5 19:22
NewDemo 发表于 2014-5-5 18:03
你说的这个毕老师在视频里讲到了,我想问的是t1等待的时候不是还没有释放锁吗,那t2是如何拿到锁并也等待 ...

java的wait吊起线程的时候会释放synchronized锁
作者: NewDemo    时间: 2014-5-5 21:11
heima_xyu 发表于 2014-5-5 19:22
java的wait吊起线程的时候会释放synchronized锁

{:2_31:}原来是这样,刚才看了下源码,里面竟然还专门给出了例子,这个wait方法要一直在循环中使用,终于解决了这个疑惑,活到老,学到老。。
作者: wyqs92    时间: 2014-5-5 21:27
  1. public class ThreadTest2 {

  2.         /**
  3.          * @param args
  4.          * 生产者消费例子实现
  5.          * 思路:1.创建一个商品资源的类,并在其中定义两个加锁的方法用于模拟生产和消费的行为 2.定义生产者和消费者的类并实现Runnable接口
  6.          * 3.主函数中创建线程并关联资源。
  7.          */
  8.         public static void main(String[] args) {
  9.                 //创建线程并关联资源
  10.                 Resource r = new Resource();
  11.                 new Thread(new Producer(r)).start();
  12.                 new Thread(new Producer(r)).start();
  13.                 new Thread(new Producer(r)).start();
  14.                 new Thread(new Producer(r)).start();
  15.                 new Thread(new Consumer(r)).start();
  16.                 new Thread(new Consumer(r)).start();
  17. //                new Thread(new Consumer(r)).start();
  18. //                new Thread(new Consumer(r)).start();
  19.         }

  20. }
  21. //创建商品的类,公共资源
  22. class Resource{
  23.         private int count = 0;//用于记录商品的编号
  24.         private boolean flag = false;//定义标记用来控制线程的运行交替
  25.         //模拟生产行为
  26.         public synchronized void set(){
  27. while(flag)//此处如果是while,它是一个循环。如果不满足就不执行。当条件满足时,向下执行wait(),下一次被唤醒之后还需要继续判断while中的条件。但是如果改为if,它表示的是判断,如果为真向下执行,就执行了wait(),当被唤醒后,它就直接执行wait()以下的语句。
  28. 还有就是你要知道wait()表示等待,它要将正在执行的线程释放其执行资格和执行权,并存储到线程池中。

  29.                      try {
  30.                                 this.wait();
  31.                         } catch (InterruptedException e) {
  32.                                 e.printStackTrace();
  33.                         }
  34.                 count++;
  35.                 flag = true;
  36.                 System.out.println(Thread.currentThread().getName()+"生产。。"+count);
  37.                 this.notifyAll();
  38.         }
  39.         //模拟消费行为
  40.         public synchronized void out(){
  41. while(!flag)
  42.                         try {
  43.                                 this.wait();
  44.                         } catch (InterruptedException e) {
  45.                                 e.printStackTrace();
  46.                         }
  47.                 flag = false;
  48.                 System.out.println(Thread.currentThread().getName()+"消费。。。。。"+count);
  49.                 this.notifyAll();
  50.         }
  51. }

  52. //生产者的类,实现接口,复写run方法
  53. class Producer implements Runnable{
  54.         private Resource r;
  55.         Producer(Resource r){
  56.                 this.r=r;
  57.         }
  58.         @Override
  59.         public void run() {
  60.                 while(true){
  61.                         r.set();
  62.                 }
  63.         }
  64. }
  65. //消费者的类,实现接口,复写run方法
  66. class Consumer implements Runnable{
  67.         private Resource r;
  68.         Consumer(Resource r){
  69.                 this.r=r;
  70.         }
  71.         @Override
  72.         public void run() {
  73.                 while(true){
  74.                         r.out();
  75.                 }
  76.         }
  77. }
复制代码





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2