07---多线程04

来源:互联网 发布:c语言开发工具 编辑:程序博客网 时间:2024/05/18 03:53
 

1.同步会产生一个问题----死锁;
 死锁就是在多线程编程中由于处理不当而造成的程序停止运行的一种状态;

2.怎么产生一个死锁呢:
 就是线程1等待线程2的结果后才会执行;而线程2等待线程1有了结果才会执行,
 这样两个线程都在等对方的结果,这样就产生了死锁;
 
 死锁是在程序运行中发生的一种状态;
  class DemoA{
   public synchronized void funA(DemoB db){
    System.out.println("DemoA--->进入DemoA的 funA方法");
    try{
     Thread.sleep(100);
     }
     catch(Exception e){
      }
    db.fun2();
    }
   public synchronized void fun2(){
    System.out.println("DemoA--->进入DemoA的 fun2方法");
    }
   }
  class DemoB{
   public synchronized void funB(DemoA da){
    System.out.println("DemoB--->进入DemoB的 funB方法");
     try{
     Thread.sleep(100);
     }
     catch(Exception e){
      }
    da.fun2();
    }
   public synchronized void fun2(){
    System.out.println("DemoB--->进入DemoA的 fun2方法");
    }
   }
  class ThreadDead implements Runnable{
   private DemoA da=new DemoA();
   private DemoB db=new DemoB();
   
   public ThreadDead(){
    new Thread(this).start();
    da.funA(db);
    }
    public void run(){
     db.funB(da);
     }
   }

  public class Demo{
   public static void main(String args[]){
    new ThreadDead();
    }
   }

3.同步有个经典的范例:生产者----消费者;
 一个线程向数据存储空间添加数据(生产者),另一个线程从数据存储空间取出
 数据(消费者);
 这个程序有两种以外需要考虑:
  1:假设生产者线程刚想数据存储空间添加了一个人的姓名,还没有添加这个人的性别;
     cpu就切换到了消费者线程,消费者线程将把这个人的姓名和上一个人的性别联系到一起;
  2:生产者放了若干数据,消费者才开始取数据,或者是,消费者;
     取完一个数据后,还没有等放到生产者放入新的数据,又重复取出已经取过的数据;

   class Person{
    String name="lid";
    String content="作者";
    }
   class Pre implements Runnable{
    private Person per=null;
    public Pre(Person per){
     this.per=per;
     }
    public void run(){
     for(int i=0;i<10;i++){
      //避免还没有取走就又进行的下一个i了,即又赋值了
      try{
       Thread.sleep(200);
       }
      catch(Exception e){
       }
      if(i%2==0){
       per.name="MLDN";
       per.content="网站";
       }
      else{
       per.name="lid";
       per.content="作者";
       }
      }
     }
    }
   class Cust implements Runnable{
    private Person per=null;
    public Cust(Person per){
     this.per=per;
     }
    public void run(){
     for(int i=0;i<10;i++){
      //加延时是为了避免还没生产完就取完了
      try{
       Thread.sleep(200);
       }
      catch(Exception e){
       }
      System.out.println(per.name+"--->"+per.content);
      }
     
     }
    }
    
    public class Demo{
     public static void main(String args[]){
      Person per=new Person();
      Pre p=new Pre(per);
      Cust c=new Cust(per);
      
      new Thread(p).start();
      new Thread(c).start();
      }
      
     }
 
  延迟加在不同的地方会出现不同的结果:
    class Person{
     String name="lid";
     String content="作者";
     }
    class Pre implements Runnable{
     private Person per=null;
     public Pre(Person per){
      this.per=per;
      }
     public void run(){
      
       if(i%2==0){
        per.name="MLDN";
       try{
        Thread.sleep(200);
        per.content="网站";
        }
       catch(Exception e){
        }
       else{
        per.name="lid";
       try{
        Thread.sleep(200);
        per.content="作者";
        }
       catch(Exception e){
        }
       }
      }
     }
    class Cust implements Runnable{
     private Person per=null;
     public Cust(Person per){
      this.per=per;
      }
     public void run(){
      for(int i=0;i<10;i++){
       //加延时是为了避免还没生产完就取完了
       try{
        Thread.sleep(200);
        }
       catch(Exception e){
        }
       System.out.println(per.name+"--->"+per.content);
       }
      
      }
     }
     
     public class Demo{
      public static void main(String args[]){
       Person per=new Person();
       Pre p=new Pre(per);
       Cust c=new Cust(per);
       
       new Thread(p).start();
       new Thread(c).start();
       }
       
      }
 
 为了避免以上的情况我们就用到了同步,将线程要操作的资源同步;
 class Person{
  private String name="lid";
  private String content="作者";
  
  public synchronized void set(String name,String content){
   try{
    Thread.sleep(100);
    }
    catch(Exception e){
     }
     
   this.name=name;
   this.content=content;
   }
  public synchronized String get(){
   try{
    Thread.sleep(100);
    }
    catch(Exception e){
     }
   return this.name+"--->"+this.content;
   }
   
  }
 class Pre implements Runnable{
  private Person per=null;
  public Pre(Person per){
   this.per=per;
   }
  public void run(){
   for(int i=1;i<10;i++){
     if(i%2==0){
      per.set("MLDN","网站");
     }
     else{
      per.set("lid","姓名");
     }
    }
    
   }
  }
 class Cust implements Runnable{
  private Person per=null;
  public Cust(Person per){
   this.per=per;
   }
  public void run(){
   for(int i=0;i<10;i++){
    System.out.println(per.get());
    }
   
   }
  }
  
  public class Demo{
   public static void main(String args[]){
    Person per=new Person();
    Pre p=new Pre(per);
    Cust c=new Cust(per);
    
    new Thread(p).start();
    new Thread(c).start();
    }
    
   }
 但是上面不能实现写一个读一个的效果,要想现实得如下:
 
 排队买票有如下两种方式:
 1.有序:一个接一个的买,第一个买完,第二个接着买;
 2.无序:一个买完之后,看谁能先到窗口,先到窗口的先买;
 这是一个正确运行的生产者----消费者的程序(注意代码顺序);
  class Person{
  private String name="lid";
  private String content="作者";
  private boolean flag=false;
  public synchronized void set(String name,String content){
   //如果为绿的则表示可以设置,否则等待:flag 为 true  
   if(flag){
    try{
     wait();
     }
    catch(Exception e){
     }
    
    }
   try{
    Thread.sleep(100);
    }
    catch(Exception e){
     }
   this.name=name;
   this.content=content;
   //唤醒其他线程
   flag=true;  
   notifyAll();
   }
  public synchronized String get(){
   //如果为红灯,怎表示可以去,否则不可以:;flag 为 false
   if(!flag){
    try{
     wait();
     }
    catch(Exception e){
     }
    
    }
   try{
    Thread.sleep(100);
    }
    catch(Exception e){
     }
   String str=this.name+"--->"+this.content;;
   flag=false;
   notifyAll();
   return str;
   }
  }
 class Pre implements Runnable{
  private Person per=null;
  public Pre(Person per){
   this.per=per;
   }
  public void run(){
   for(int i=1;i<10;i++){
     if(i%2==0){
      per.set("MLDN","网站");
     }
     else{
      per.set("lid","姓名");
     }
    }
    
   }
  }
 class Cust implements Runnable{
  private Person per=null;
  public Cust(Person per){
   this.per=per;
   }
  public void run(){
   for(int i=1;i<10;i++){
    System.out.println(per.get());
    }
   
   }
  }
  
  public class Demo{
   public static void main(String args[]){
    Person per=new Person();
    Pre p=new Pre(per);
    Cust c=new Cust(per);
    
    new Thread(p).start();
    new Thread(c).start();
    }
    
   }

4.线程的停止问题:
 线程中的几个方法:
 start()----启动一个线程:也就是执行run()方法;
 sleep()----线程的休眠;
 wait()-----线程的等待;
 resume:要求被暂停的线程继续执行;
 suspend:暂停线程的执行;
 yield:将执行的权力交给其他的线程,自己到队列的最后等待;
 
 控制线程声明周期的方法很多,如:suspend方法、resume方法、
 stop方法,不推荐使用suspend和resume方法以为:
  1.会导致死锁的发生;
  2.他允许一个线程(甲)通过直接控制另一线程(乙)的代码来直接控制那个线程(乙)
 虽然stop能够避免死锁的发生,但是带来了另外的不足,如果一个线程正在操作共享数据段,操作
 过程没有完成就stop的话,将会导致数据的不完整性,所以stop方法也不提倡使用;
 
 

原创粉丝点击