第五讲
多线程
●     在多任务系统中,每个独立执行的程序称为进程,也就是“正在进行的程序”。我们现在使用的操作系统一般都是多任务的,即能够同时执行多个应用程序,实际情况是,操作系统负责CPU等设备的资源进行分配和管理,虽然这些设备某一时刻只能做一件事,但以非常小的时间间隔交替执行多个程序,就可以给人以同时执行多个程序的感觉。
●     一个进程中又可以包含一个或多个线程,一个线程就是一个程序内部的一条执行线索,如果要一程序中实现多段代码同时交替运行,就需产生多个线程,并指定每个线程上所要运行的代码段,这就是多线程。
 
用Thread类创建线程
●     要将一段代码在一个新的线程上运行,该代码应该在一个类的run函数中,并且run函数所在的类是Thread类的子类。倒过来看,我们要实现多线程,必须编写一个继承了Thread类的子类,子类要覆盖Thread类中的run函数,在子类的run函数中调用想在新线程上运行的程序代码。
●     启动一个新的线程,我们不是直接调用Thread的子类对象的run方法,而是调用Thread子类对象的start(从Thread类中继承到的)方法。Thread类对象的start方法将产生一个新的线程,并在该线程上运行该Thread类对象的run方法。根据面向对象的运行时的多态性,在该线程上实际运行的是Thread子类(也就是我们写的那个类)对象中的run方法。
●     由于线程的代码段在run方法中,那么该方法执行完成以后线程也就相应的结束了,因而我们可以通过控制run方法中的循环的条件来控制线程的结束。
   
class SubThread extends Thread
{
       public void run()
       {
              while(true)
              {
                     System.out.println("SubThread: "+Thread.currentThread().getName());
              }
       }
}
 
class TestThread
{
       public static void main(String[]args)
       {
              //SubThread st=new SubThread();
              //st.start();
              new SubThread().start();
              while(true)
              {
                     System.out.println("main: "+Thread.currentThread().getName());
              }
       }
}
 
后台线程与联合线程
●     如果我们对某个线程对象在启动(调用start方法)之前调用了setDaemon(true)方法,这个线程就变成了后台线程。
●     对java程序来说,只要还有一个前台线程在运行,这个进程就不会结束,如果一个进程中只有后台线程运行,这个进程就会结束。
class ThreadDemo1
{
              public static void main(String[]args)
 
              { 
                            Thread tt=new TestThread();
                            tt.setDaemon(true);
                            tt.start();//run();     
              }
}
 
class TestThread extends Thread
{ 
              public void run()
              { 
                            while(true)
                            {
                                         System.out.println("run():"+Thread.currentThread().getName());
                            } 
              }
}
●     pp.join()的作用是把pp所对应的线程合并到调用pp.join();语句的线程中。
例如:
class ThreadDemo1
{
              public static void main(String[]args)
 
              { 
                            Thread tt=new TestThread();
                            //tt.setDaemon(true);
                            tt.start();
                            int index=0;
                            //在index=100后,tt线程join主线程中,主线程停止。在tt线程运行10秒后,主线程和tt线程又交替运行。join()中也可不带参数。
                            while(true)
                            {
                                          if(++index==100)
                                                        try{tt.join(10000);}catch(Exception e){}
                                         System.out.println("mian():"+Thread.currentThread().getName());
                            }     
              }
}
 
class TestThread extends Thread
{ 
              public void run()
              { 
                            while(true)
                            {
                                         System.out.println("run():"+Thread.currentThread().getName());
                            } 
              }
}
实现Runnable接口的多线程方法
class ThreadDemo1
{
              public static void main(String[]args)
 
              { 
                            //Thread tt=new TestThread();
                            //tt.setDaemon(true);
                            Thread tt=new Thread(new TestThread());
                            tt.start();
                            int index=0;
                            //在index=100后,tt线程join主线程中,在tt线程运行10秒后,主线程和tt线程交替运行。join()中也可不带参数。
                            while(true)
                            {
                                          if(++index==100)
                                                        try{tt.join(10000);}catch(Exception e){}
                                         System.out.println("mian():"+Thread.currentThread().getName());
                            }     
              }
}
 
class TestThread implements Runnable//extends Thread
{ 
              public void run()
              { 
                            while(true)
                            {
                                         System.out.println("run():"+Thread.currentThread().getName());
                            } 
              }
}
使用Runnable接口创建多线程
●     适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码、数据有效分离,较好地体现了面向对象的设计思想。
●     可以避免由于Java的单继承性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了其一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能继承Thread类的方式,那么,这个类只能采用实现Runnable。
●     当线程被构造时,需要的代码和数据通过一个对象作为构造函数的实参传递进去,这个对象实现了Runnable接口的类的实例。
●     事实上,几乎所有多线程应用都可用Runnable接口方式。
class ThreadDemo1
{
              public static void main(String[]args)
              { 
                            TestThread t=new TestThread();
                            new Thread(t).start();
                            new Thread(t).start();
                            new Thread(t).start();
                            new Thread(t).start();
              }
}
 
class TestThread implements Runnable
{ 
              //int tickets=100;
              int tickets=1;
              public void run()
              { 
                            /*while(true)
                            {
                                          if(tickets>0)
                                                       System.out.println("run():"+Thread.currentThread().getName()+"   "+tickets--);
                            } */
                            for(;tickets<101;tickets++)
                            {
                                          System.out.println("run():"+Thread.currentThread().getName()+"    "+tickets);
                            }
              }
}
 
多线程的同步
● 使用同步代码块来实现线程的同步
class ThreadDemo1
{
              public static void main(String[]args)
              { 
                            TestThread t=new TestThread();
                            new Thread(t).start();
                            new Thread(t).start();
                            new Thread(t).start();
                            new Thread(t).start();
              }
}
 
class TestThread implements Runnable
{ 
              String str=new String("");
              int tickets=100;
              //int tickets=1;
              public void run()
              { 
                            while(true)
                                          {
                                                        synchronized(str)
                                                        {
                                                                      if(tickets>0)
                                                                                    {
                                                                                                  try
                                                                                                  {
                                                                                                                Thread.sleep(10);
                                                                                                  }catch(Exception e)
                                                                                                  {
                                                                                                                e.printStackTrace();
                                                                                                  }
                                                                                                 System.out.println("run():"+Thread.currentThread().getName()+"   "+tickets--);
                                                                                   }
                                                        }
                                          } 
                            /*synchronized(str)
                            {
                                          for(;tickets<101;tickets++)
                                          {
                                                        try{Thread.sleep(10);}catch(Exception e){e.printStackTrace();}//让线程暂停10毫秒
                                                        System.out.println("run():"+Thread.currentThread().getName()+"    "+tickets);
                                          }
                            }*/
                            
              }
}
● 使用同步函数来实现线程的同步
class ThreadDemo1
{
              public static void main(String[]args)
              { 
                            TestThread t=new TestThread();
                            new Thread(t).start();
                            new Thread(t).start();
                            new Thread(t).start();
                            new Thread(t).start();
              }
}
 
class TestThread implements Runnable
{ 
              int tickets=100;
              public void run()
              { 
                            while(true)
                                          {
                                                        sale();
                                          }                   
              }
              public synchronized void sale()
              {
                            if(tickets>0)
                            {
                                          try{Thread.sleep(10);}catch(Exception e){e.printStackTrace();}//让线程暂停10毫秒
                                          System.out.println("run():"+Thread.currentThread().getName()+"   "+tickets--);
                      }
              }
}
● 代码块与函数间的同步
class ThreadDemo1
{
              public static void main(String[]args)
              { 
                            TestThread t=new TestThread();
                            new Thread(t).start();
                            try{Thread.sleep(1);}catch(Exception e){}
                            t.str="method";
                            new Thread(t).start();
                            
              }
}
 
class TestThread implements Runnable
{ 
              String str=new String("");
              int tickets=100;
              public void run()
              { 
                            if(str.equals("method"))
                            {
                                          while(true)
                                          {
                                                        sale();
                                          }     
                            }
                            else
                            {
                                          while(true)
                                          {
                                                        synchronized(this)
                                                        {
                                                                      if(tickets>0)
                                                                      {
                                                                                    try{Thread.sleep(10);}catch(Exception e){e.printStackTrace();}//让线程暂停10毫秒
                                                                                    System.out.println("run():"+Thread.currentThread().getName()+"   "+tickets--);
                                                                }
                                                        }
                                          }
                            }
                                          
              }
              public synchronized void sale()
              {
                            if(tickets>0)
                            {
                                          try{Thread.sleep(10);}catch(Exception e){e.printStackTrace();}//让线程暂停10毫秒
                                          System.out.println("method():"+Thread.currentThread().getName()+"   "+tickets--);
                      }
              }
}
线程间的通信
●     wait:告诉当前线程放弃监视器并进入睡眠状态直到其他线程进入同一监视器并调用notify为止。
●     notify:唤醒同一对象监视器中调用wait的第一线程。用于类似饭馆有一个空位后通知所有等候就餐的顾客中的第一位可以入座的情况。
●     notifyAll:唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。
例:一线程向缓冲区中不断放入”zhangsan”,”male”和”lisi”,”female”,另一线程不断从缓冲中取走数据。
线程通信例程1:(在下面例程2的基础上修改而来)
class Producer implements Runnable
{
              Q q;
              public Producer(Q q)
              {
                            this.q=q;
              }
              public void run()
              {
                            int i=0;
                            while(true)
                            {
                                          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)
                            {
                                          q.get();
                            }
              }
}
 
class Q
{
                     private String name="unknown";
                     private String sex="unknown";
                     private boolean bFull=false;//设置缓冲区状态,空
                     public synchronized void put(String name,String sex)
                     {
                                   if(bFull)//如果缓冲区为满(true),线程进入睡眠状态
                                                 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();
                            
              }
}
 
//sleep((int)(Math.random() * 100));
线程通信例程2:
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(Exception e){}
                                                        //else
                                                        //{
                                                                      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();
                                                        //}
                                                 
                                          }
                                          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){}
                                                        //else不能用else语句。
                                                        //{
                                                                      System.out.print(q.name);
                                                                      System.out.println(":"+q.sex);
                                                                      q.bFull=false;
                                                                      q.notify();
                                                        //}
                                                        
                                          }
 
                            }
              }
}
 
class Q
{
                     String name="unknown";
                     String sex="unknown";
                     boolean bFull=false;
}
 
class ThreadCommunation
{
              public static void main(String[]args)
              {
                            Q q=new Q();
                            new Thread(new Producer(q)).start();
                            new Thread(new Consumer(q)).start();
                            
              }
}
 
//sleep((int)(Math.random() * 100));
 
 
 
线程的生命的控制
●     程序中如何控制线程的生命
class ThreadTest implements Runnable
{
              private boolean bStop=false;
              public void stop()
              {
                            bStop=true;
              }
              public void run()
              {
                            while(!bStop)
                            {
                                          System.out.println(Thread.currentThread().getName()+"is running.");
                            }
              }
}
 
class TestThread
{
              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.stop();
                                          }
                                          System.out.println(Thread.currentThread().getName());
                            }
              }
}