关闭

java学习笔记(九)----多线程

标签: javathreadexceptionclassstring多线程
1433人阅读 评论(0) 收藏 举报
分类:

class ThreadDemo1
{ public static void main(String[] args)
  { new TestThread().start(); //用start()默认去调用run()方法
    while(true)
    { System.out.println("main():"+Thread.currentThread().getName()); }
  }
}
class TestThread extends Thread
{ public void run()
  { while(true)
    { System.out.println("run():"+Thread.currentThread().getName()); }
  }
}

1.要将一段代码在一个新的线程上运行,该代码应该在一个类的run函数中,并且run函数所在的类是Thread的子类。 倒过来看,我们要实现多线程,必须编写一个继承了Thread类的子类,子类要覆盖Thread类中的run函数,在子类的run函数中调用想在新线程上运行的程序代码。
2.启动一个新的线程,我们不是直接调用Thread子类对象的run方法,而是调用Thread子类对象的start(从Thread类的继承到的)方法,Thread类对象的start方法将产生一个新的线程,并在该线程上运行该Thread类对象中的run方法。
3.由于线程的代码段在run方法中,那么该方法执行完成以后线程也就相应的结束了,因而我们可以通过控制run方法中循环的条件来控制线程的结束.
----------------------------------------------------------------------------------
***后台线程***
class ThreadDemo1
{ public static vioid main(String[] args)
  { Thread tt=new TestThread();
    tt.setDaemon(true);  //在start()前加了setDaemon(true)方法,run()中的线程就变成了后台线程
    tt.start();
    while(true)
    { System.out.println("main():"+Thread.currentThread().getName()); }
  }
}
class TestThread extends Thread
{ public void run()
  { while(true)
    { System.out.println("run():"+Thread.currentThread().getName()); }
  }
}
说明了,java中只有后台线程,没有前台线程,java程序就会结束。
1.如果我们对某个线程对象在启动(调用start方法)之前调用了setDaemon(ture)方法,这个线程就变成了后台线程。
2.对java程序来说,只要有一个前台线程在运行,这个进程就不会结束,如果一个进程中只有后台线程运行,这个进程就会结束。
-----------------------------------------------------------------------------
***主线程和子线程的合并***
class ThreadDemo1
{ public static vioid main(String[] args)
  { Thread tt=new TestThread();
    tt.setDaemon(true); 
    tt.start();
    int index=0;
    while(true)
    { if(index++==100)
           try{tt.join();} catch(Exception e){}  //此处会有异常,所以必须用try,catch
   //当主线程运行100遍以后,就把tt对象的线程加入主线程,又成为单线程了,只有tt对象的线程执行完以后,才会继续执行main中的主线程。
 //  try{tt.join(10000);} catch(Exception e){} 当主线程和子线程合并100000毫秒后,在分开运行
      System.out.println("main():"+Thread.currentThread().getName());
    }
  }
}
class TestThread extends Thread
{ public void run()
  { while(true)
    { System.out.println("run():"+Thread.currentThread().getName()); }
  }
}

---------------------------------------------------------------------------------------------------------
***创建线程另一种方法,用Runnable接口***
class ThreadDemo1
{ public static vioid main(String[] args)
  { Thread tt=new Thread(new TestThread()); //创建一个thread的对象, 当线程对象启动时,它就不调用thread类中自带的run()方法,而记为调用Runnalbe中的run()方法
    tt.start();
    int index=0;
    while(true)
    { if(index++==100)
           try{tt.join();} catch(Exception e){} 
      System.out.println("main():"+Thread.currentThread().getName());
    }
  }
}
class TestThread implements Runnable //它继承Runnable接口,Runnable接口就有一个run()方法 
{ public void run()
  { while(true)
    { System.out.println("run():"+Thread.currentThread().getName()); }
  }
}
----------------------------------------------------------------------------------------
***用多个线程,去执行一段代码***
帖路售票,四个窗口同时卖100张票,需要四个线程一同去执行一段代码。

class ThreadDemo1
{ public static void main(String[] args)
  { new TestThread().start();
  new TestThread().start();
  new TestThread().start();
  new TestThread().start();
   /*这样就是4个线程,但每个线程都是执行各自的代码,它们是在卖各自的100张票,并不是同时执行一段代码。
   应改为
  TestThread tt=new TestThread();
    tt.start();
    tt.start();
    tt.start();
    tt.start();这样还是不行,因为这样就算写再多tt.start()它还是一个线程,
  将main中代码改为
  TestThread tt=new TestThread();
    new Thread(tt).start();
    new Thread(tt).start();
    new Thread(tt).start();
    new Thread(tt).start();
  只有让TestThread类继承Runnable类,这样写才是四个线程一起去执行同一段代码*/
  }
}
class TestThread extends Thread 改为 class TestThread implements Runnable
{ int tickets=100;
  public void run()
  { while(true)
    { if(tickets>0) 
       { try{Thread.sleep(10);} catch(Exception e){}  //Thread.sleep(10)让该线程停10毫秒,其它线程继续执行
         System.out.println(Thread.currentThread().getName()+"is saling ticket"+tickets--);
       }
    }
  }
}
***使用Runnable接口创建多线程***
1.适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码、数据有效分离,较好地体现了面向对象的设思想
2.可以避免由于java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable
接口。
3.当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例   (这句看不太懂)
4.事实上,几乎所有多线程应用都可用Runnable接口方式。

----------------------------------------------------------------------------
----------------------------------------------------------------------------
***************多线程的同步*******************
class ThreadDemo1
{
  TestThread tt=new TestThread();
    new Thread(tt).start();
    new Thread(tt).start();
    new Thread(tt).start();
    new Thread(tt).start();
  
  }
}
class TestThread implements Runnable
{ int tickets=100;
  public void run()
  { while(true)
    { if(tickets>0) 
       { try{Thread.sleep(10);} catch(Exception e){}  //Thread.sleep(10)让该线程停10毫秒,其它线程继续执行
         System.out.println(Thread.currentThread().getName()+"is saling ticket"+tickets--);
       }
    }
  }
}
//上面的程序在执行时,就会打印出负数来
 把TestThread 类改为
 class TestThread implements Runnable
 {  int tickets=100;
     String str=new String(""); //为synchronized定义的对象, 这个对象的定义必须放在run()方法的外面,不能放在里面,如果放里面的话,每个线程调用时,都产生一个新的str对象,这样,每个线程的str对象每回的标志都是1开始,它就失去了synchronized的功能,运行后还会出现负数。
    public void run()
   { while(true)
     { synchronized(str)   //将代码放入synchronized语句内,形成了同步代码块,在同一时刻只能有一个线程可以进入同步代码块内运行,当该线程离开同步代码块后,其他线程才能进入同步代码块。 synchronized(object){代码块}这里的object可以是任意一个对象。
    { if(tickets>0) 
         { try{Thread.sleep(10);} catch(Exception e){}
           System.out.println(Thread.currentThread().getName()+"is saling ticket"+tickets--);
         }
        }
     }
   } 
 }

//还可以把上面的TestThread改为

 class TestThread implements Runnable
 {  int tickets=100;
    
    public void run()
   { while(true)
      { sale(); }
   } 
   public synchronized void sale() //这样调用也可以,在sale()方法前加上synchronized,这样运行后就不会有负数, 这个方法是用this作为同步监视器的。
    {  if(tickets>0)
       { try(Thread.sleep(10);) catch(Exception e){}
          System.out.println(Thread.currentThread().getName()+"is saling ticket"+tickets--);
       }
    }
 }
-------------------------------------------------------------------
***代码块与函数间的同步***
class ThreadDemo1
{
  TestThread tt=new TestThread();
    new Thread(tt).start();
   try{Thread.sleep(1);}  catch(Exception e) {} //让cpu延迟一毫秒,第一个线程就会去运行run()方法中的内容
    tt.str=new String("method");
    new Thread(tt).start();
  }
}
class TestThread implements Runnable
 {  int tickets=100;
     String str=new String(""); 
    public void run()
   { if(str.equals("method")
    {
         while(true)
         { sale();
         }
       }
      else 
       { while(true)
         { synchronized(this)  //此处注意,不能用str,这样就和sale方法用的是同一个对象了,这样就能实现同步了  
       { if(tickets>0) 
           { 
           System.out.println(Thread.currentThread().getName()+"is saling ticket"+tickets--);
           }
           }
         }
      } 
  
      public synchronized void sale()
    {  if(tickets>0)
       { try(Thread.sleep(10);) catch(Exception e){}
     System.out.print("sale():") 
          System.out.println(Thread.currentThread().getName()+"is saling ticket"+tickets--);
       }
    }
 }
注意:1. 如果没能 try{Thread.sleep(1);}  catch(Exception e) {}语句,最后就是所有线程都去调用sale方法,但加了这条语句,不管停多久,cpu就会马上去运行run()方法中的内容。
2. synchronized(this) 这里必须用this,代码块与函数间才能用相同的对象作为同步监视器。
----------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------
***线程间的通信***
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)
                   try{q.wait();} catch(Exeption e){}
                  if(i==0)
                  { q.name="zhangsan"
               try{Thread.sleep(1);} catch(Exception e){}
               q.sex="male";
                }
                  else
                  { q.name="lisi";
                     q.sex="female";
                  }
                  q.bFull=true;
                  q.notify();
                } */
                      // 在Q类中加了put和get方法后,上面注释的代码可改为
            ---------------------------------------------------
                          if (i==0)
                            q.put("zhangsan","male")
                          else
                            q.put("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 e){} 
                     System.out.print(q.name);
                     System.out.println(":"+q.sex);
                     q.bFull=false;
                     q.notify();
                   } */
               // 在Q类中加了put和get方法后,上面注释的代码可改为
                  --------------------------------------------------
                  q.get();
                  --------------------------------------------------  
    }
  }
}

class Q
{ String name="unknown";   // private String name="unknown"; 
  String sex="unknown";    // private String sex="unknown"; 
 boolean bFull=false;     // private boolean bFull=false;
 -------------------------------------------------------------
  ** public synchronized void put(String name,String sex)
  { if (bFll)
          try{ wait(); }  catch(Exception e){}
    this.name=name;
    try{Thread.sleep(1);}  catch(Exception e) {}
    this.sex=sex;
     bFull=true;
    notify();
  }
  ** public synchronized void get()
  {  if (!bFull) 
            try{ wait(); }  catch(Exception e){}
     System.out.print(name);
     System.out.println(":"+sex);
       bFull=false;
      notify();       
  }
  -------------------------------------------------------------
}

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

--Object对象包括三个方法
 wait: 告诉当前线程放弃临视器并进入睡眠状态直到其它线程进入同一监视器并调用notify为止。
 notify:唤醒同一对象监视器中调用wait的第一个线程。用于类似饭馆有一个空位后通知所有等候就餐的顾客中的第一个可以入座的情况
 notifyAll: 唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。用于类拟某个不定期的培训班终于招生满额后,通知所有学员都来上课的情况。

----------- 
| thread t|
-----------
     |
----------------- 
|synchronized(o)| 线程t得到对象o的lock旗标 
-----------------
     |
-----------
|o.wait() | 此时线程t被放置在对象o的等待线程池中,t自动释放o的锁旗标
-----------
     |
------------
|o.notify()| 当另外的线程执行了对象o的notify()方法后,线程t可能会被从o的等待线程池中释放出来,并且移动到等
------------ 待线程对象o的锁旗标的线程池中,当t得到锁旗标时就会执行下去


-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
***线程的生命控制***
class ThreadCommunation
{ public static void main(String[] args)
   { ThreadTest tt=new ThreadTest();
     new Thread(tt).start();
     for(int i=0; i<100;i++)
     { if (i==50)
           tt.stopMe();  // 在第一个线程循环50次后,使第二个线程停下来
       System.out.println("main() is running");
     }
   }
}
class ThreadTest implement Runnable
{ private boolean bStop=false;
  public void stopMe()
  { bStop=false; }
  public void run()
  {  while(bStop)
     { System.out.println(Thread.currentThread().getName()+"is running"); }

---------------------------------------------
---------------------------------------------
---------------------------------------------
tt.setDaemon(true);    Runnalbe     synchronized(this)      
try{tt.join(10000);} catch(Exception e){} 当主线程和子线程合并100000毫秒后,在分开运行
try{Thread.sleep(10);} catch(Exception e){}  //Thread.sleep(10)让该线程停10毫秒,其它线程继续执行
wait()   notify()  

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1230023次
    • 积分:9025
    • 等级:
    • 排名:第2151名
    • 原创:120篇
    • 转载:222篇
    • 译文:1篇
    • 评论:143条
    最新评论