黑马程序员——多线程代码实践及一些思考

------- android培训java培训、期待与您交流! ----------

一、懒汉式单列设计模式中的安全问题

解决一个类在内存只存在一个对象的设计模式中想要保证唯一性。单列设计模式很恰当的解决了这一问题。单例设计模式有饿汉式和懒汉式两种方式。懒汉式只有对象被调用时才被初始化,也称对像的延迟加载。与饿汉方式区别也在于此,饿汉创建对象就初始化操作。

懒汉式在多线程控制中有安全隐患。如何避免这一安全隐患,显得很重要。

为了解决多线程中的安全隐患,在懒汉式代码中加入了同步方法synchronized()。使用同步函数,在函数方法上加入synchronized。这样,可以解决多线程中的安全隐患。但是,从程序执行效率考虑,每个进程会多次都会判断对你调用是否初已经初始化,从而运行效率大大降低。通过以snchronized(){}同步代码块的,进一步提高了程序的执行效率。详细代码如下:

 

classSingle

{

         private static s = null;

         private Sigle(){}

         public static Single getInstance()

         {

                   if(s==null)

                   {

                            synchronized(Single.class)

                            {

                                     if(s==null)

                                               retruns ;

                                     }

                   }

                   return s ;

                   }       

}


扩展程序:

用饿汉式实现四个线程卖票小程序实例

//懒汉式(延迟加载)

classSingal implements Runnable

{

         private Singal(){}

         private static Singal s =null;

         private int ticket = 100;

         public static Singal getInstance()//用同步函数也可以实现同步,但效率比较低

         {

                   if(s==null)

                   {

                            synchronized(Singal.class)//双重判断 提高了效率

                            {

                                     if(s==null)

                                               s= new Singal();

                                     return s;

                            }

                   }

                   return s;

                  

         }

 

         public void run()

         {

                   while(true)

                   {

                            synchronized(Singal.class)

                            {

                                     if(ticket>0)

                                     {

                                               //for(int x=0;x<100 ;x++ )//逻辑错误这样写 只会运行一个线程

                                               //{

                                                        try{Thread.sleep(100);}catch(Exceptione){} //延时操作,以遍4个进程都有运行到(由于本笔记本多核处理哭,数据太少而输出又快,有可以用不完四个进程,所以延时以达到效果)

                                                        System.out.println(Thread.currentThread().getName()+":"+ticket--);

                                               //}

                                     }

                            }                          

                           

                   }

                  

         }

 

}

 

 

class  SingalTicket

{

         public static void main(String[] args)

         {

 

                   Singal s =Singal.getInstance();

                   Thread t1 = new Thread(s);

                   Thread t2 = new Thread(s);

                   Thread t3 = new Thread(s);

                   Thread t4 = new Thread(s);

                  

                   t1.start();

                   t2.start();

                   t3.start();

                   t4.start();

 

         }

}

 

二、生产者与消费者

用四个线程实现,两个生产者生产产品后,另两个消费者消费。要求生产一个产品必须先消费才能再生产下一个商品。

分析:生产者与消费者之前有共享资源(产品);且有多个线程(两个生产者与两个消费者)参与其中;生产者生产过程和消费过程都会使用到产品。以上三点,可以判断整个过程会引发安全隐患。我只需将双方使用产品的过程进行同步实现即可解决这个问题,这个安全隐患。程序代码如下

class  ProduceConsumerDemo

{

         public static void main(String[] args)

         {

                   Resource r = new Resource();

                   Thread t1 = new Thread(newProduce(r));

                   Thread t2 = new Thread(newConsumer(r));

                   Thread t3 = new Thread(newProduce(r));

                   Thread t4 = new Thread(newConsumer(r));

                  

                   t1.start();

                   t2.start();

                   t3.start();

                   t4.start();

 

                   /*

                   new Thread(newProduce(r)).start();

                   new Thread(newConsumer(r)).start();

                   new Thread(newProduce(r)).start();

                   new Thread(newConsumer(r)).start();

                   */

         }

}

 

classResource

{

         private String name;

         private int count = 1;

         private boolean flag;

         //t1和t2拥有不同的锁(Produce和Consumer对像),因此能够进入set函数内

         public synchronized void set(Stringname)//同步函数的锁是this,在这里this代表它所在类Resource的引用(即调用都是对象)

         {

                   //if(flag)  //换while,那么问题就来了,程序会停住。这时,唤醒方式改成notifyAll就可以解决。                                                 

                                                        //考虑如何处理?想到反复判断flag不就解决了,因此用while(flag)替换if(flag)

                                               //  t1放弃资格 t2获取资格//当t2获取资格后就不再判断flag,这样会出现还没消费掉t1生产的商品他t2就紧接着生产。

                   while(flag)try{this.wait();}catch(Exception e){}

                   this.name =name+"----"+count++;

                   System.out.println(Thread.currentThread().getName()+"--生产者--"+this.name);

                   flag = true;

                   //this.notify();//notify唤醒的是池中的第一个等待中的线程 notifyAll唤醒池中所有等待中的进程

                   this.notifyAll();

         }

 

         //t1和t2拥有不同的锁(Produce和Consumer对像),因此能够进入out函数内

         public synchronized void out()//同步函数的锁是this,在这里this代表它所在类Resource的引用(即调用都是对象)

         {

                   /*if(!flag)*/

                                                 t1放弃资格 t2获取资格

                   while(!flag)       try{this.wait();}catch(Exception e){}

                   System.out.println(Thread.currentThread().getName()+"--消费者--------"+name);

                   flag = false;

                   //this.notify();

                   this.notifyAll();

         }

}

 

classProduce implements Runnable

{

         Resource r = new Resource();

         Produce(Resource r)

         {

                   this.r = r;

         }

         public void run()

         {

                   while(true)

                   {

                            r.set("商品");

                   }

         }

        

}

classConsumer implements Runnable

{

         Resource r = new Resource();

         Consumer(Resource r)

         {

                   this.r = r;

         }

         public void run()

         {

                   while(true)

                   {

                            r.out();

                   }

         }

        

}

 


为实现同步,加入同步函数后发现。程序并达到没有预期的要求(产品必须先消费才能再生产下一个商品)。为达到这个目的,首先分析问题所在。经验证发现在使用产品过程中,同步函数监视器(锁)只能监视共同使用一个监视器的进程才有效,即无法监视具有不同监视器的对象。所以会导致程序中t1和t2对象判断语句判断后停留在那里,这样还会带来安全隐患。因此,为了达到多次判断,我们选择使用while循环语句。当然,引入while循环语句会带来程序停留的问题,不过使用Objec中的唤醒机制中的notifyAll完美解决了这个问。其中,一定要注意使用notify唤醒为什么会程序停留,因为其唤醒的只是池中的第一个进程。这样不难分析,其中生产者与消费者会多次使用产品的问题,而不是目标所要求的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值