1. 什么是线程协作
    有些情况下,多个线程合作完成一件事情的几个步骤,此时线程之间实现了协作。如一个工作需要若干个步骤,各个步骤都比较耗时,不能因为他们的运行,影响程序的运行效果,最好的方法就是将各个步骤用线程实现。但是,由于线程随时都有可能抢占cpu,可能在前面一个步骤没有完成时,后面的步骤就已经运行,该安全隐患造系统得不到正确结果。
  2. 一个案例
    线程1负责完成一个复杂运算(比较耗时),线程2负责得到结果,并将结果进行下一步处理。

       比如,某个科学计算系统中,线程1负责计算1---100000各个数字的和,线程2负责得到这个结果并且写入数据库。用传统方法编写这段代码如下:

public class ThreadCooperateTest
{
 private long sum =0;
 class CalThread extends Thread
 {
  public void run()
  {
   for(int i =1;i<100000;i++)
   {
    sum +=i;
   }
  }
 }
 class SaveThread extends Thread
 {
  public void run()
  {
   System.out.println("写入数据库: sum ="+sum);
  }
 }
  public void work()
 {
  CalThread ct = new CalThread();
  SaveThread st = new SaveThread();
  ct.start();
  st.start();
 }
 public static void main(String[] args)
 {
  new ThreadCooperateTest().work();
 }
 
}
public class ThreadCooperateTest
{
 private long sum =0;
 class CalThread extends Thread
 {
  public void run()
  {
   for(int i =1;i<100000;i++)
   {
    sum +=i;
   }
  }
 }
 class SaveThread extends Thread
 {
  public void run()
  {
   System.out.println("写入数据库: sum ="+sum);
  }
 }
  public void work()
 {
  CalThread ct = new CalThread();
  SaveThread st = new SaveThread();
  ct.start();
  st.start();
 }
 public static void main(String[] args)
 {
  new ThreadCooperateTest().work();
 }
 
}

运行结果,发现不正确,而且每次输入的结果不一样。这是因为,当线程ct运行后,线程st运行,此时线程st随时可能抢占cpu,而不一定要等线程ct运行完毕。此时,在求和还没有开始做或者只完成了一部分时,就打印出来sum,所以结果错误。

解决这个错误,要用到join()方法,代码如下:

public class ThreadCooperateTest
{
 private long sum =0;
 class CalThread extends Thread
 {
  public void run()
  {
   for(int i =1;i<100000;i++)
   {
    sum +=i;
   }
  }
 }
 class SaveThread extends Thread
 {
  public void run()
  {
   System.out.println("写入数据库: sum ="+sum);
  }
 }
  public void work()
 {
  CalThread ct = new CalThread();
  SaveThread st = new SaveThread();
  ct.start();
  /*
   ThreadCooperateTest.java:27: 未报告的异常 java.lang.InterruptedException;必须对
   其进行捕捉或声明以便抛出
                ct.join();
                       ^
    1 错误
  ct.join();必须要catch其异常
  */
  try
  {
   ct.join();
  }catch(Exception e)
  {}
  st.start();
 }
 public static void main(String[] args)
 {
  new ThreadCooperateTest().work();
 }
 
}
public class ThreadCooperateTest
{
 private long sum =0;
 class CalThread extends Thread
 {
  public void run()
  {
   for(int i =1;i<100000;i++)
   {
    sum +=i;
   }
  }
 }
 class SaveThread extends Thread
 {
  public void run()
  {
   System.out.println("写入数据库: sum ="+sum);
  }
 }
  public void work()
 {
  CalThread ct = new CalThread();
  SaveThread st = new SaveThread();
  ct.start();
  /*
   ThreadCooperateTest.java:27: 未报告的异常 java.lang.InterruptedException;必须对
   其进行捕捉或声明以便抛出
                ct.join();
                       ^
    1 错误
  ct.join();必须要catch其异常
  */
  try
  {
   ct.join();
  }catch(Exception e)
  {}
  st.start();
 }
 public static void main(String[] args)
 {
  new ThreadCooperateTest().work();
 }
 
}

解决方法:

在运行线程ct时,命令另一个线程st等待线程ct运行完毕,才能抢占cpu进行运行。在java语言中,只需要调用线程ct的join()方法,就能够让系统等起运行完毕才能运行下面的代码。这次输出的结果正确了。


注意:

实际上,该程序相当于摒弃了“线程就是为了程序看起来同时做好几件事情”的思想,将并发程序又变成了顺序的,如果线程ct没有运行完毕的话,程序会在ct.join()处堵塞。如果work耗时较长,程序将一直等待。解决方式是,可以将work函数放在另一个线程中,既不会堵塞主程序,又能够保证数据安全性。

练习:将例子中的work函数写在另外一个线程内,在主函数中调用

代码如下:

public class ThreadCooperateTest
{
 private long sum =0;
 class CalThread extends Thread
 {
  public void run()
  {
   for(int i =1;i<1000000;i++)
   {
    sum +=i;
   }
  }
 }
 class SaveThread extends Thread
 {
  public void run()
  {
   System.out.println("写入数据库: sum ="+sum);
  }
 }
  public void work()
 {
  CalThread ct = new CalThread();
  SaveThread st = new SaveThread();
  ct.start();
  /*
   ThreadCooperateTest.java:27: 未报告的异常 java.lang.InterruptedException;必须对
   其进行捕捉或声明以便抛出
                ct.join();
                       ^
    1 错误
  ct.join();必须要catch其异常
  */
  try
  {
   ct.join();
  }catch(Exception e)
  {}
  st.start();
 }
 public static void main(String[] args)
 {
  
  
  Thread t = new Thread()
  {
   public void run()
   {
    new ThreadCooperateTest().work();
   }
   
  };
  t.start();
  
 
 }
 
}
public class ThreadCooperateTest
{
 private long sum =0;
 class CalThread extends Thread
 {
  public void run()
  {
   for(int i =1;i<1000000;i++)
   {
    sum +=i;
   }
  }
 }
 class SaveThread extends Thread
 {
  public void run()
  {
   System.out.println("写入数据库: sum ="+sum);
  }
 }
  public void work()
 {
  CalThread ct = new CalThread();
  SaveThread st = new SaveThread();
  ct.start();
  /*
   ThreadCooperateTest.java:27: 未报告的异常 java.lang.InterruptedException;必须对
   其进行捕捉或声明以便抛出
                ct.join();
                       ^
    1 错误
  ct.join();必须要catch其异常
  */
  try
  {
   ct.join();
  }catch(Exception e)
  {}
  st.start();
 }
 public static void main(String[] args)
 {
  
  
  Thread t = new Thread()
  {
   public void run()
   {
    new ThreadCooperateTest().work();
   }
   
  };
  t.start();
  
 
 }
 
}