且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

java多线程的同步 通信以及生产消费者问题

更新时间:2022-08-13 08:22:47

Demo1

/*   Runable接口比直接从Thread继承方便的多  。 
*    new  Thread(...) ;这样即使我们传递了同一个实现了Runnable接口的多个对象那么 也是多个线程 ,而且多个线程共享数据域.
*    否则new Thread 创建的多个线程之间 互不相干  ,数据之间互不干涉
*    同步就是为了实现 在多个线程同时对一个资源进行操作的时候 要一个一个的执行 ,
*    只有等占有CPU的 线程完事之后 其他等待线程才能进入就绪状态等待运行
*    java中可以用 synchrozined(Object obj){}      实现代码块的同步      参数是任意对象 
*    不但可以利用synchronized语句块  也可以在方法的前面 声明 synchronized      
*    同步原理是对象的标志位 初始为1  当进入代码块后 obj的标志位变为 0  这时候其他线程则不能 进入代码块执行 而进入等待状态
*    直到先进入的那个线程完事然后就会为这个线程解锁 。 其他线程才可能开始运行   火车票的售票系统就是一个多线程很好的运用的例子
*    同步是以程序的性能为代价的   ,同步方法是以类的this对象为同步对象的  而 synchronized块是以我们指定的对象为 同步对象
*    如果想让代码块和同步方法同步那么 使用的同步对象 必须都为this
*/  
public class  ThreadDemo2
{
   public static void main(String []args)
   {
       MyThread mt=new MyThread() ;  
       //mt.start() ;
       new Thread(mt) .start() ;
       try
      {
       Thread.sleep(10) ; //每当产生一个线程CPU不会立马去执行 ,这之间既有一个微小的时间间隔 。
      }
      catch(Exception e)
      {
       System.out.println(e.toString()) ;
      }
       mt.str="method";
       new Thread(mt) .start() ;
   }
}
class  MyThread    implements Runnable// extends   Thread
{  
   int tickets=100 ;
   String str=new String("");
   public void run()
   {
       if(str.equals("method"))
       {
        while(true)
        {
         running() ;
        }
       }
       else
       {
        while(true)
        {
         synchronized(str)
        {
         if(tickets>0 )
         {
          System.out.println("block:"+Thread.currentThread().getName()+"sells"+tickets--);
         }
        }
         
        }
       }
   }
   public  synchronized  void running()
   {    
      if(tickets>0) 
       {
        try{Thread.sleep(10);}catch(Exception ex){}
        System.out.print("method:") ;
        System.out.println(Thread.currentThread() +"sell " + tickets-- ) ;
       }
   }
}  

 

Demo2:

/*
*   java多线程中 有前台线程和后台线程,前台线程 是指 main所在的主线程 和其他 创建的线程 ,如果在线程调用start 之前调用  setDeamon(true)
*   那么 这个线程就是一个后台线程,在进程中如果没有一个前台线程 那么后台线程也随之退出,从而进程也退出 。如果没有调用setDeamon(true)或者
*   调用setDeamom(false)那么这个线程就是前台线程 ,只要一个进程中还存在前台线程 那么即使mian方法所在的线程退出了 ,那么这个前台子线程也会继续执行
*   直至退出  。
*   Tread类额join方法 是将一个线程合并到另一个线程中, 可以设置合并的时间间隔
*   我们实现自己的线程类有2中方法  :
*   1、直接从Thread继承而来  实现 run方法  。
*   2、实现Runnable接口,并且实现run方法 。 Thread  th=new Thread(....) ;//吧我们自己实现的类的对象作为参数传进去   .
*   join 方法可以将一个线程合并到另一个线程 中 而且还可以指定线程合并的时间间隔
*
*/
public  class  ThreadDemo1
{
      public static  void main(String[]args) 
      {
        //MyThread tt=new MyThread() ; tt.start() ;可以从 Thread类派生一个线程类
        Thread tt=new Thread(new MyThread()) ;  //可以通过Thread类的带参数的构造方法 传递一个实现了Runnable接口的对象
   //     tt.setDaemon(true) ;//将线程设置为 后台线程  主线层退出这个线程也会随着退出 
        tt.start() ;
        int index=0 ;
        while(true)
        {
         if(index++==100)
         try{
           tt.join(5000) ;
         }
         catch(Exception ex)
        {
         System.out.println(ex.toString()) ;
        }
          
         System.out.println("run:"+Thread.currentThread().getName()) ;
        }
      }

}
class  MyThread  implements Runnable//extends    Thread
{
    public void run()
    {
      while(true)
      {
      System.out.println("run:"+Thread.currentThread().getName()) ;
      }
    }
}

Demo3:

/*   线程之间的通信是协调线程同步的重要方法   、
*    Object类的 wait方法通告同步对象进入等待状态,直到其他线程得到同步对象 并且调用 notity方法 ,等待线程才会继续执行
*    notify方法 是通告同步对象的等待线程进入恢复运行 
*    notifyAll通告所有堵塞线程恢复运行
*     下面是一个生产消费者的问题   ,在对于类的操作的时候 一定要有面向对象的思想  。  否则 就会非常的杂乱
*/
class  Producer  implements  Runnable
{
 Q q  ;
 public Producer(Q q)
 {
  this.q=q ;
 }
 public  void run()
 { 
    int i=0 ;
    while(true)
    {
    /* synchronized(q)
     {
      if(q.bFull==true)
          try{q.wait() ;}catch(Exception ex){}
         if(i==0)
     {
       q.name="zhangsan" ;
       try{
       Thread.sleep(1) ;
      }catch(Exception ex){}
       q.sex="male"  ;
     }
     else
     {
      q.name="lisi"  ;
      q.sex="female" ;
     }  
     q.bFull=true ;
     q.notify() ;
    }
     i=(i+1)%2 ;
     */ 
   
     if(i==0 )
      q.push("zhangsan","male");
       else
      q.push("lisi","female") ;  
      i=(i+1)%2 ;
    }
      
 }
}
class Consumer implements  Runnable 
{  
   Q q ;
   public Consumer(Q q)
   {
    this.q=q ;
   }
   public   void  run()
   {
      while(true)
     {
     /*  synchronized(q)
       {
         if(!q.bFull)
         {
        try{q.wait() ;}catch(Exception ex){}
          }
          System.out.println(q.name+":"+q.sex) ;
          q.bFull=false ;
           q.notify() ;
        }
      */
      q.get() ;
     }
   }
}

class  Q   //以面向对象的思想对线程之间的通信进行封装从而实现消费者 生产社的问题
{
 String name="unknown"  ;
 String sex ="unknown"  ;
 boolean bFull=false ;
 public synchronized void push(String name,String sex)
 {     
      if(this.bFull==true)
               try{wait() ;}catch(Exception ex){}
       this.name=name ;
       this.sex=sex   ; 
       bFull=true ;
       try{notify() ;}catch(Exception ex){}
 }
 public synchronized void get()
 {
  if(this.bFull==false)
     try{wait() ;}catch(Exception ex){}
  System.out.println("name:"+this.name+" sex:"+this.sex) ;
     bFull=false ;
     try{notify() ;}catch(Exception ex){}
 }
}


class  ThreadTest  implements  Runnable    //这个线程类 来模拟线程的声明结束  因为Thread类的 stop suspend等方法都已经过时了
{                                          //所以有时候我们对于线程的开始和结束要自己设置标志位来
  boolean bRun=true ;
  int index=0 ;
  public  void  stopMe()
  {
   bRun=false ;
  }
  public  void run()
  {
   while(bRun)
   { 
      if(++index>100)
        stopMe() ;
     System.out.println(Thread.currentThread().getName()+" is running!");
   }
  
   }
 
}

public  class  ThreadDemo3
{
  
   public static void main(String[]args)
   {
    
   Q q=new Q() ;
    new Thread(new Producer(q)).start() ;
   new Thread(new Consumer(q)).start() ; 
 
   }
}