(十)Core Java 多线程(通信) (99)

 目录 :           


1 ) . 多线程(线程间通信--示例代码)

2 ) .  多线程(线程间通信--解决安全问题)

3 ) .   多线程(线程间通信--等待唤醒机制)

4 ) .  多线程(线程间通信--代码优化)

5 ) .  多线程(线程间通信--生产者消费者)

6 ) .  多线程(线程间通信--生产者消费者升级版)

7 ) .   多线程(停止线程)

8 ) .    多线程(守护线程)

9 ).     多线程(Join方法)


     一 .  多线程(线程间通信--示例代码)

1 ) . 图解 : 


1.1 思考 : wait() ,notify(),notifyAll(),用来操作线程为什么定义在Object类中?

[1] 这些方法存在于同步中

[2]使用这些方法时必须要标识所属的同步的锁

[3] 锁可以是任意对象,所以任意对象调用的方法一定定义Object类中

1.2 思考2 : wait(),sleep()有什么区别?

[1] wait() : 释放资源,释放锁

[2] sleep():释放资源,不释放锁 

2 ) . Demo :   -->解决方式在下一章

 
 /*
       一个输入功能,一个输入功能,一个资源池,,然后有规律的输入输出
       
    同一个对象向inputStream存入,同一个对象在outputstream取出

       出现了以下问题: 存入内容的与取出的内容相互混乱,涉及多线程问题
 
  */
 
 
  class Resources
  {
         String name;
         String sex;
  }
 
 
  class InputStream implements Runnable
  {
         private Resources res;
        
         InputStream(Resources res)
         {
               this.res=res;
         }
        
         public void run()
         {    
              int num=0;
               while(true)
               {
                      if(num==0)
                      {
                           synchronized(this)
                             {
                                    res.name="summer";
                                    res.sex="man";
                             }
                      }
                      else
                      {
                             synchronized(this)
                             {
                                        res.name="小王";
                                        res.sex="妞";
                             }
                      }
                     
                      num=(num+1)%2;
               }
              
         }
  }
 
  
  class OutputStream implements Runnable
  {
        
         private Resources res;
        
         OutputStream(Resources res)
         {
               this.res=res;
         }
          
         
         public void run()
         {
               while(true)
               {
                       synchronized(this)
                       {
                                  System.out.println(res.name+"........"+res.sex);
                       }
               }
              
         }
  }
  
 
  class InputOutputDemo
  {
      public static void main(String args[])
      {
             Resources r = new Resources();
             Thread in = new Thread(new InputStream(r));
             Thread ou = new Thread(new OutputStream(r));
             in.start();
           ou.start();
         }           
  }

    这是出现的问题
 
小结 :  

             1.  当多个人共用一个功能的时候,这个功能可以封装成方法或者封装成类
     
 

       二. 多线程(线程间通信--解决安全问题)


1 ) . 分析是否同步的两个维度 : 

1.1 是否是两个或两个以上的线程

1.2 是否使用的是同一个锁

2 ) . Text :   --> 现象就是-->同时输入同时输出

 
 /*
       一个输入功能,一个输入功能,一个资源池,然后有规律的输入输出
       
    同一个对象向inputStream存入,同一个对象在outputstream取出
       出现了以下问题: 存入内容的与取出的内容相互混乱,涉及多线程问题;
       
       解决方式:
       
       通过同步代码块解决同步问题(多个进程同时进行的问题),通过唯一的资源当作锁解决多个进程使用同一个锁的问题

        出现了以下问题 : 并不是一个输入一个输出有规律的输出,见下一章解决
 
  */
 
 
  class Resources
  {
         String name;
         String sex;
  }
 
 
  class InputStream implements Runnable
  {
         private Resources res;
        
         InputStream(Resources res)
         {
               this.res=res;
         }
        
         public void run()
         {    
              int num=0;
               while(true)
               {
                           synchronized(Resources.class)
                           {
                                   if(num==0)
                                               {
                                                res.name="summer";
                                                res.sex="man";
                                               }
                                        else
                                               {
                                               res.name="小王";
                                               res.sex="妞";
                                               }
                                        num=(num+1)%2;
                           }
                     
                    
               }
              
         }
  }
 
  
  class OutputStream implements Runnable
  {
        
         private Resources res;
        
         OutputStream(Resources res)
         {
               this.res=res;
         }
          
         
         public void run()
         {
               while(true)
               {
                      synchronized(Resources.class)
                           {
                                  System.out.println(res.name+"........"+res.sex);
                           }
               }
              
         }
  }
  
 
  class InputOutputDemo1
  {
      public static void main(String args[])
      {
             Resources r = new Resources();
             Thread in = new Thread(new InputStream(r));
             Thread ou = new Thread(new OutputStream(r));
             in.start();
           ou.start();
         }           
  }

 
小结 :  

             1.  想使用唯一一个对象掌控不同的功能,就把实例化对象给提出来,而后通过参数的方式放入不同的实现类中
        
       


      三. 多线程(线程间通信--等待唤醒机制)

1 ) .问题:

问题一 :  以下三个方法都是使用在同步中,因为都要对持有监视器(锁)的线程进行操作,因此需使用在同步中,因为只有同步才具有锁

1.1 wait()

1.2 notify()

1.3 notifyAll()

问题二 : 为何以上操作线程方法要定义在Object类中呢?

因为在操作同步中的线程时,都必须得标识所操作线程的锁,而同一个锁上被等待的线程,只能被同一个锁上的notify唤醒,不可对不同锁上的线程唤醒,

而锁又可以是任意对象,所以可被任意对象调用的方法都定义在Object类中 

2 ) . Text :  --> 该代码完善添加了等待唤醒机制


 
 /*
       一个输入功能,一个输入功能,一个资源池,然后有规律的输入输出
       
    同一个对象向inputStream存入,同一个对象在outputstream取出
       出现了以下问题: 存入内容的与取出的内容相互混乱,涉及多线程问题;
       
       解决方式:
       
       通过同步代码块解决同步问题(多个进程同时进行的问题),通过唯一的资源当作锁解决多个进程使用同一个锁的问题
       
    出现了以下问题 : 并不是一个输入一个输出有规律的输出
       
       解决方式 :
       
       通过在不同线程使用相同资源的情况下,采用等待唤醒机制一个一个来的方式解决 ,例子 :  关于定的游戏
 
  */
 
 
  class Resources
  {
         String name;
         String sex;
         boolean flag =false;
  }
 
 
  class InputStream implements Runnable
  {
         private Resources res;
        
         InputStream(Resources res)
         {
               this.res=res;
         }
        
         public void run()
         {    
              int num=0;
               while(true)
               {
                           synchronized(Resources.class)  //resources.class 也可填 res  ,也就是构造函数传进来的那个对象是一个的, 重点就是使用同一个锁
                           {
                                 //唤醒机制
                                 if(res.flag)
                                        try{Resources.class.wait();}catch(Exception e){}   //resources.class 也可填 res  ,也就是构造函数传进来的那个对象是一个的, 重点就是使用同一个锁
                                                 if(num==0)
                                                            {
                                                             res.name="summer";
                                                             res.sex="man";
                                                            }
                                                     else
                                                            {
                                                            res.name="小王";
                                                            res.sex="妞";
                                                            }
                                                     num=(num+1)%2;
                                        res.flag=true;
                                        Resources.class.notify();  //resources.class 也可填 res ,也就是构造函数传进来的那个对象是一个的 , 重点就是使用同一个锁
                           }      
             }
                     
                    
       }
}
 
 
  
  class OutputStream implements Runnable
  {
        
         private Resources res;
        
         OutputStream(Resources res)
         {
               this.res=res;
         }
          
         
         public void run()
         {
               while(true)
               {
                      synchronized(Resources.class) //resources.class 也可填 res  ,也就是构造函数传进来的那个对象是一个的, 重点就是使用同一个锁
                           {            
                                 //唤醒机制
                                 if(!res.flag)
                                        try{Resources.class.wait();}catch(Exception e){} //resources.class 也可填 res  ,也就是构造函数传进来的那个对象是一个的, 重点就是使用同一个锁
                                                      System.out.println(res.name+"........"+res.sex);
                                 res.flag=false;
                                 Resources.class.notify();   //resources.class 也可填 res  ,也就是构造函数传进来的那个对象是一个的, 重点就是使用同一个锁
                           
                           }
               }
              
         }
  }
  
 
  class InputOutputDemo2
  {
      public static void main(String args[])
      {
             Resources res = new Resources();
             Thread in = new Thread(new InputStream(res));
             Thread ou = new Thread(new OutputStream(res));
             in.start();
           ou.start();
         }           
  }


 
小结 :  

             1.  等待的线程会放入线程池中,一般情况下唤醒的是最先等待的线程
        
           2.  IllegalMonitorStateException  -->当前线程不含有当前对象的锁资源的时候,使用wait()notify()notifyAll()都会抛出

           3. 切记 : 使用等待唤醒机制时,切记让其等待的锁与让其唤醒的锁是同一个锁,而不同线程可使用同一个锁,若不是同一个锁就会抛出上条的异常

          
 

      四. 多线程(线程间通信--代码优化)

1 ) . 代码优化的六大原则 : 

1.1 单一职责 -->  各司其职

1.2   开闭原则  -->对于扩展(类,模块,函数)是开放的,对于修改是封闭的

1.3   里氏替换原则  --> 里氏替换原则就是基于这两个字:抽象,也就是所有引用基类(最多的共性类)的地方,必须能使用子类对象-->抽出共性形成类

1.4 -->依赖倒置原则 -->高层模块是调用端,底层模块就是具体实现类,高层模块与底层模块之间不依赖,统一依赖抽象模块-->也就是面向接口或面向抽象编程

1.5  -->接口隔离原则-->指将非常庞大,臃肿的接口抽取出更小的接口和更具体的接口,目的是 系统解开耦合,从而容易重构,更改和重新部署

1.6  -->迪米特原则 --> 也是最少知识原则,指一个对象应该对其他对象有最少的了解 -->

我翻译的就是 知道的越多死的越快(两者关系密切臃肿,后期还得自己先捋清关系,再修改代码),还不如知道的少点

1.7小知识点 : 

[1] 抽象就是指接口和抽象类,因为两者不可被直接实例化 



2 ) . Text :  -->完整版,优化过的

 
 /*
       一个输入功能,一个输入功能,一个资源池,然后有规律的输入输出
       
    同一个对象向inputStream存入,同一个对象在outputstream取出
       出现了以下问题: 存入内容的与取出的内容相互混乱,涉及多线程问题;
       
       解决方式:
       
       通过同步代码块解决同步问题(多个进程同时进行的问题),通过唯一的资源当作锁解决多个进程使用同一个锁的问题
       
    出现了以下问题 : 并不是一个输入一个输出有规律的输出
       
       解决方式 :
       
       通过在不同线程使用相同资源的情况下,采用等待唤醒机制一个一个来的方式解决 ,例子 :  关于定的游戏
       
       
       代码优化
 
  */
 
  //设值与输出值两者涉及同步代码块与等待唤醒机制,
  class Resources
  {
           private  String  name;
           private  String  sex;
             private  boolean flag = false;
        
         //为对象进行设值
         public synchronized void set(String name,String sex)
         {
               if(flag)
                      try{this.wait();}catch(Exception e){}
               else
               {
                      this.name=name;
                      this.sex=sex;
               }
              
                     this.flag=true;
                     this.notify();                  
              
         }
        
         //为对象值进行输出
          public synchronized void out()
         {
               if(!flag)
                        try{this.wait();}catch(Exception e){}
                else
                           System.out.println(this.name+"......"+this.sex);
                    
                    this.flag=false;
                    
                    this.notify();                   
                    
              
         }
       
  }
 
  //输入流,进行调取对象方法输入值
  class InputStream implements Runnable
  {
         private Resources res;
        
         InputStream(Resources res)
         {
               this.res=res;
         }
        
         public void run()
         {    
              int num=0;
             
               while(true)
               {
                      if(num==0)
                                  res.set("summer","man");
                           else
                                 res.set("小王","妞");
                           
                           num=(num+1)%2;
             }
                     
                    
       }
}
 
 
   //输出流,进行调取对象方法输出值
  class OutputStream implements Runnable
  {
        
         private Resources res;
        
         OutputStream(Resources res)
         {
               this.res=res;
         }
          
         public void run()
         {
               while(true)
               {
                           res.out();
               }
         }
  }
  
 
 //主函数
  class InputOutputDemo3
  {
      public static void main(String args[])
      {
             //创建资源对象
             Resources res = new Resources();
             //创建一个输入线程,其中内含写入资源对象值,并启动-->其中写入的是res对象的值
           new Thread(new InputStream(res)).start();
             //创建一个输出线程,其中内含写出资源对象值,并启动-->其中写出的也是res对象的值
             new Thread(new OutputStream(res)).start();
       
         }           
  }
 
 
小结 :  

             1.  优化时采取模块化的方式,如何思考模块化,就是思考在其位谋其政,思考自己做自己本分事即可
 
     五 .  多线程(线程间通信--生产者消费者)

1 ) . 业务思考四思路 : -->与以下代码无关

1.1 要求的结果是什么?

1.2 形成的结构是什么?

1.3 要使用那些知识点?

1.4 要满足哪些条件 ? 

2 ) . Text-->ProducerConsumerDemo

/*
       需求:ProducerConsumer,生产一个,消费一个
       
       当四个线程时,会出现下边常见两个问题:
       问题1.出现生产者1生产的产品1没有被消费
       问题2.出现消费者重复消费了生产者生产的产品1
       
       分析原因:
       原因1:if(flag)不能循环判断,因此当同一个锁中有两个线程时,一个被激活,而后再另一个被激活时是不需要再判断直接运行下边代码了
       原因2:this.notify()是用来唤醒的,但唤醒的是先等待的线程,当那个不需要再次验证的线程被激活后就直接执行下边的代码了
       解决 :
       
       if(flag)改成while(flag) -->循环判定,就算进入等待,被激活后也得重新判断 -->但是这个会出现全部等待的问题
       this.notify()改成this.notifyAll()-->摆脱先唤醒先等待线程这个局限,全部唤醒,再次进入正循环即可  -->全部唤醒解决了上个全部等待问题
       
*/
//主函数
  class ProducerConsumerDemo
  {
      public static void main(String args[])
      {
               Product pro = new Product();
               new Thread(new Producer(pro)).start();
               new Thread(new Consumer(pro)).start();
               new Thread(new Producer(pro)).start();
               new Thread(new Consumer(pro)).start();
              
              
       
         }           
  }
  //产品
  class Product
  {    
         private int count=1;
         private String ProductName;
         private boolean flag=false;
       public synchronized void set(String ProductName)
       {      
             while(flag)  //if(flag)      t1 ,t2
                    try{this.wait();}catch(InterruptedException e){}
             this.ProductName=ProductName+"--"+count++;
             
             System.out.println(Thread.currentThread().getName()+"...........生产者"+count);
             
             this.flag=true;
             this.notifyAll();
       }      
       
       
       public synchronized void out()
       {
             
             while(!flag) //if(flag)   t3 , t4
                           try{this.wait();}catch(InterruptedException e){}
                    System.out.println(Thread.currentThread().getName()+"消费者...."+count);
                    
                    this.flag=false;
                    this.notifyAll();
       }      
  }
 
 
  //生产者
  class Producer implements Runnable
  {
         private Product pro;
        
         Producer(Product pro)
         {
               this.pro=pro;
              
         }
         public void run()
         {
               while(true)
                    {
                           pro.set("summer");
                    }
         }
        
  }
 
 
  //消费者
  class Consumer implements Runnable
  {
         private Product pro;
         Consumer(Product pro)
         {
               this.pro=pro;
              
         }
         public void run()
         {
               while(true)
             {
                           pro.out();
             } 
         }
        
  }
 
  


3 ) .  生产者与消费者用到的知识点 :  同步代码块 , 等待激活机制 , 多线程循环判定问题

4 ).问题:

4.1 对于多个生产者和消费者为何要定义while判断标记?

[1] 让唤醒的线程再一次判断标记

4.2 对于多个生产者消费者为何要定义notifyAll? 

[1] 因为需要唤醒对方的线程,通过notify易出现只唤醒本方线程的情况,导致所哟线程都等待,因此通过notifyAll唤醒所有的线程


小结 :  

             1.  学习方法 : 

[1] 彻底理解问题

[2] 形成解决思路

[3]立即动手执行

[4]不断总结迭代
        
           2.  if(flag) 是判断一次, while(flag)是判断多次

           3. 全部等待跟死锁的区别在于,全部等待是都没有执行权全部冻结,死锁是具有执行权,但是A锁锁住了B锁,不是一个锁

  

       六.  多线程(线程间通信--生产者消费者升级版)


1 ) . JDK1.5新特性 :  -->提供了多线程升级版解决方案在 java.util.concurrent.locks包中

1.1  Condition 接口封装了之前的object对象的wait(),notify(),notify()等方法

1.2 Lock接口实现了开启锁,关闭锁的封装方法,将同步Synchronized替换掉了,实现了同一个condition等待唤醒同一个进程

白话 : Acondition让B进程等待,只能Acondition才能唤醒B进程

2 ) . Text : 

import java.util.concurrent.locks.* ;
/*
       需求:ProducerConsumer,生产一个,消费一个
       
       当四个线程时,会出现下边常见两个问题:
       问题1.出现生产者1生产的产品1没有被消费
       问题2.出现消费者重复消费了生产者生产的产品1
       
       分析原因:
       原因1:if(flag)不能循环判断,因此当同一个锁中有两个线程时,一个被激活,而后再另一个被激活时是不需要再判断直接运行下边代码了
       原因2:this.notify()是用来唤醒的,但唤醒的是先等待的线程,当那个不需要再次验证的线程被激活后就直接执行下边的代码了
       解决 :
       
       if(flag)改成while(flag) -->循环判定,就算进入等待,被激活后也得重新判断
       this.notify()改成this.notifyAll()-->摆脱先唤醒先等待线程这个局限,全部唤醒,再次进入正循环即可
       
             
       优化,使用JDK5.0的并发新特性优化代码
       
*/
//主函数
  class ProducerConsumerDemo1
  {
      public static void main(String args[])
      {
               Product pro = new Product();
               new Thread(new Producer(pro)).start();
               new Thread(new Consumer(pro)).start();
               new Thread(new Producer(pro)).start();
               new Thread(new Consumer(pro)).start();
 
         }           
  }
  //产品
  class Product
  {    
         private int count=1;
         private String ProductName;
         private boolean flag=false;
         //创建一个锁对象,用来开启锁和关闭锁
         private Lock lock =  new ReentrantLock();      
         //创建两个条件分别用于不同的锁上用来等待和唤醒
      private Condition conditionA =lock.newCondition();
         private Condition conditionB =lock.newCondition();

 
       public void set(String ProductName) throws InterruptedException
       {      
             lock.lock();
             try
             {
                    
                    while(flag)  
                            conditionA.await();
                    this.ProductName=ProductName+"--"+count++;
                    
                    System.out.println(Thread.currentThread().getName()+"...........生产者"+count);
                    
                    this.flag=true;
                     conditionB.signal();
             }
             finally
             {
                    
                    lock.unlock();
             }
    
       }      
       
       
       public void out() throws InterruptedException
       {
             lock.lock();
              try
             {
                    while(!flag) //if(flag)   t3 , t4
                                  conditionB.await();
                           System.out.println(Thread.currentThread().getName()+"消费者...."+count);
                           
                           this.flag=false;
                            conditionA.signal();
             }
             finally
             {
                    lock.unlock();
             }
                    
       }      
  }
 
 
  //生产者
  class Producer implements Runnable
  {
         private Product pro;
        
         Producer(Product pro)
         {
               this.pro=pro;
              
         }
         public void run()
         {
               while(true)
                    {
                           try
                           {
                                 pro.set("summer");
                    
                           }
                           catch(InterruptedException e)
                           {
                                 
                                 
                           }
                    
                    }
         }
        
  }
 
 
  //消费者
  class Consumer implements Runnable
  {
         private Product pro;
         Consumer(Product pro)
         {
               this.pro=pro;
              
         }
         public void run()
         {
               while(true)
             {
                    
                           try
                           {
                                 pro.out();
                    
                           }
                           catch(InterruptedException e)
                           {
                                 
                                 
                           }
             } 
         }
        
  }
 
 
 
 
 
 
 
 
 


3 ) .  相关以上代码接口方法须知 :

3.1 Lock lock =  new ReentrantLock();    -->用来通过reentrantlock实例化类来获取一个锁对象来使用 lock() 和 unlock() 方法

3.1 Condition conditionA =lock.newCondition();  -->用来创建一个关于 调用等待和唤醒方法的类,其中此类还可多次创建,是A开启A,B开启B的模式

3.3  切记 , 一般封装后的新功能都会在名字上加一些修改, 例如:封装后的 wait()名字是await();

 

4 ) . java中不可以被NEW的类 : 

4.1 抽象类

4.2 接口

4.3 无公开的构造方法类

4.4 虚接口(抽象接口)


小结 :  

             1.  JDK5.0以后的加入了并发时的新特性显性的锁机制和显性的等待唤醒机制
        
           2.  查看JDKAPI5.0以后的  软件包 java.util.concurrent.locks  看详细并发时可采用的方法

      

      七.  多线程(停止线程)

1 ) . 概述 : 

1.1 定义循环结束标记 --> 因为线程运行代码一般都是循环,只要控制了循环即可

1.2 使用interrupt(中断)方法-->该方法是结束线程的冻结状态,使线程回到运行状态中来

ps : stop()方法已经过时,不再使用

2 ) . 线程结束方式 : 

2.1 基本方式 :  多线程的运行通常都是循环结构,通过控制有限循环体则就可让run方法结束,也就是线程结束

2.2 特殊情况 : 当线程处于了冻结状态,并没有指定的方式让冻结的线程恢复到运行状态时,采用清除冻结的方式,强制让线程恢复到运行状态中来,这样就可通过操作标记让线程结束 

3 ) .  Demo  :

 
/*
        需求:结束线程方式
        方式: 通过waiti()进行挂起,然后通过interrupt()的方法中断异常
       
*/
 
 class ThreadA implements Runnable
 {
       private boolean flag =true;
        public synchronized void run()
        {
              while(flag)
             {
                    try
                    {
                           wait();
                    }
                    catch(InterruptedException e)
                    {
                           flag=false;
                    }
                    
                           System.out.println(Thread.currentThread().getName()+"......runThread.......");
             
             }      
              
        }
       
        public void changeFlag()
        {
              flag=false;
             
        }
 
 }
 
 
 
  class StopThread
  {
      public static void main(String args[])
      {
       
             ThreadA st = new ThreadA();
             Thread t1 =  new Thread(st);
             t1.start();
             t1.interrupt();
             
             
             //     Thread t2 =  new Thread(st);
             //     t2.start();
             //t2.interrupt();
             
       /*     int num=0;
             
             while(true)
             {
                     if(num++ ==1)
                     {
                           //st.changeFlag();
                           t1.interrupt();
                           t2.interrupt();
                            break;
                    
                     }
                    
              //System.out.println(Thread.currentThread().getName()+"......main......."+num); 
       
             }*/
         }           
  }
 

 

小结 :  

             1.  中断状态就是冻结状态,绝非停止了进程
        
           2.  停止线程的方式是先用wait()方法冻结,在用interrupt()方法停止

        
 

     八 多线程(守护线程)

1 ) . 概述 : 

1.1 守护线程就是后台线程

1.2 当前台线程都结束的时候,后台线程会自动结束,jvm虚拟机退出

1.3 声明守护线程-->   new Thread(new 自定义线程对象()).setDeamon(true);  -->也就是将已有线程调用.setDeamon(true)方法并设参数值为true声明守护线程

2 ) . 使用场景 :

2.1 当一个A线程依赖另一个B线程时,B线程消失,则A线程存在就没意义了,可将A线程设置为守护线程

 
小结 :  

             1.  详情见JDK的API的Thread的方法
        
   
          

     九 .   多线程(Join方法)

1 ) . 概述

1.1 简述 : join是加入的意思,准确来说是 争夺PU执行权的意思

1.2 特点 : 引用了join()方法的线程会获得CPU的执行权,将自己的可行代码执行完,主线程(JVM虚拟机)需要等该线程挂了之后才能再次分配CPU执行权

2 ) . Demo : 

 
/*
        需求:抢夺CPU资源的方法
        方式:  join()方法
        特点:当A线程执行到了B线程的.join()方法时,A就会等待,等待B线程都执行完,A才会执行,也可理解为B在强制抢CPU资源
        使用: join可以用来临时加入线程执行
       
       
*/
class Demo implements Runnable
{
       public void run()
       {
             for(int i=0;i<60;i++)
             {
                    System.out.println(Thread.currentThread().getName()+"runNable...."+i);
             }
       }
       
}
 
 
  class JoinThread
  {
      public static void main(String args[])  throws InterruptedException
      {
             Demo   demo = new Demo();
             Thread t0   = new Thread(demo);
             Thread t1  = new Thread(demo);
             t0.start();
             t0.join();//在这里加这句话,意味着t0抢占了CPU执行权,必须把to该运行的线程代码全部运行完再往下运行
             t1.start();
             
             
         }           
  }
 

 
 
 

  
   十 .    总结


1 ) . 如何多个线程共享一个数据

1.1  方式一 : 通过static 声明的方式 ,但 并不是所有情况都可用

1.2  方式二 : 通过实现Runnable接口来完成多个线程共享一个数据

2 ) .如何解决多线程情况下的数据错乱问题?

2.1 使用同步代码块同步线程,从而解决多线程安全问题

2.2 使用同步函数来同步线程,从而解决多线程安全问题

3 ).如何解决单例中的懒汉模式的对象实例化安全问题?

3.1 通过将实例化对象的那几段代码放入同步代码块,切记同步函数锁用的是this,静态同步函数锁用的是字节码文件对象

4 ). 如何解决死锁的问题?

4.1 死锁的产生是因为同步中嵌套同步,避免A嵌套B,B嵌套A的情况发生即可,若发生可通过以下方式解决

[1] 查看是否是两个或两个以上线程

[2] 查看两个线程用的是否是同一个锁

5 ).如何完成一个输入一个输出同时进行呢?

5.1 确保两个线程用的是同一个锁

5.2 使用同步代码块实现多个线程使用的是同一个锁的问题

5.3 使用等待唤醒机制解决一个输入过后一个再输出有规律的进行

 

6 ).简单阐述下生产者消费者的思路 : 

6.1 通过lock开启锁和关闭锁

6.2 通过condition实现等待唤醒机制

6.3 通过try{}finally{}保证锁的执行权拿到后必须得再交出去

6.4 通过while的循环判定解决if的局限性,摆脱全部等待问题


7). 如何让线程停止?

7.1  通过waiti()进行挂起,然后通过interrupt()的方法中断异常

8).守护线程是什么?

8.1 A依赖B,B消失则A失去意义的线程,此时A是守护线程,常用于后台程序,可通过set.Deamon(true)的方法来设置守护线程

9). 如何用线程抢占CPU资源?

9.1 通过Thread中的方法join()来设置抢占资格,获取CPU执行权





  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值