Picses' sky

Picses' sky
posts - 43, comments - 29, trackbacks - 0, articles - 24

java线程简单介绍[zz]

Posted on 2007-07-18 10:55 Matthew Chen 阅读(660) 评论(2)  编辑  收藏 所属分类: Java MultiThread

在java中,一个线程用一个Thread对象表示
一般每一个java程序都有一个main方法(applet没有),它是主线程的入口点
而用Thread表示的线程,入口点自然不是main了,而是run方法
定义一个线程,主要就是写它的run方法
写run有两种方法,一种是继承Thread类,然后重写它的run
另一种是实现Runnable接口,然后重写它的run,如下所示:
============================
//用外部类实现多线程
class  ThreadTest2
{
 public static void main(String[] args)
 {
  new ThreadTest2();
 }
 ThreadTest2(){
  for(int i=1; i<=5; i++){
   System.out.println("creating thread "+i);
   outterThread th = new outterThread(i);//创建新线程
   th.start();//启动刚创建的线程
  }
 }
}

class outterThread extends Thread//通过继承Thread类来实现多线程;外部类
{
 int count;
 outterThread(int i){
  count = i;
 }
 public void run() {
  while(true){
   System.out.println("thread "+count+" is running");
   try{
    sleep(1000*count);
   }
   catch(InterruptedException e){}
  }
 }
}
=====================================
class ThreadTest3 implements Runnable //通过实现Runnable接口来实现多线程
{
 int count;
 public static void main(String[] args)
 {
  for(int i=1; i<=5; i++)
   //调用了Thread类的构造函数Thread(Runnable target)
   new Thread(new ThreadTest3(i)).start();
 }
 ThreadTest3(int i){
  System.out.println("creating thread "+i);
  count = i;
 }
 public void run(){
  while(true){
   System.out.println("thread "+count+" is running");
   try{
    Thread.sleep(1000*count);//让线程睡眠一段时间
   }
   catch(InterruptedException e){}
  }
 }
}
可以看到,不论如何重写run,都要生成Thread对象.不同的是,第二种方法要在Thread的构造函数里传入Runnable的实现类作为参数
上面的例子还用到了start()和sleep()
前者用作启动线程,调用它之后,run方法就开始执行;后者使线程暂停参数指定的时间,单位是毫秒.这个sleep会抛出异常,所以要有try,catch块
===========================
在上面的例子中,在for循环中创建的线程和主线程是并列的,一个线程的结束不会影响另一个线程
在上面的例子中,执行完for循环,主线程就结束了,而其他线程还在运行着
用setDaemon()可以使一个线程作为后台线程执行,也就是说,当其他非Daemon线程结束时,不论run执行完没有,后台线程也将退出
反过来,你也可以使主线程等待其他线程结束后再退出.注意这里是主线程等待其他线程结束,而上面讲的daemon线程是在所有非daemon(主线程和其他非daemon)退出后再退出.要实现这一目的,可使用join().它可带可不带参数,带参数的话, 参数表示等待时间,如果过了这指定的时间不管join了的线程退出与否,主线程都会结束(如果main方法已经执行完了)
下面是例子
=======================
class DaemonAndJoin
{
 public static void main(String[] args)
 {
  Thread th = new Thread( new Runnable(){ 
   int count = 2;
   public void run(){
    while(count>0){
     for(int i=0; i<5; i++){
      try{
       Thread.sleep(500);
       System.out.println("in thread 1 ");
      }catch(InterruptedException e){
       e.printStackTrace();
      }
     }
     count--;
     System.out.println("one for is done");
    }
   }
  });
  Thread th2 = new Thread(new Runnable(){
   public void run(){
    while(true){
     try{
      Thread.sleep(1000);
      System.out.println("in thread 2");
     }catch(InterruptedException e){
      e.printStackTrace();
     }
    }
   }
  });
  System.out.println("main thread begins");  
  th.start(); 
  th2.setDaemon(true);//设置后台线程
  th2.start();
  try{
   th.join();//join
  }catch(InterruptedException e){
   e.printStackTrace();
  }
  System.out.println("main thread quits");
 }
}
==============
上面例子,如果没有th这个线程,th2和主线程都会很快结束
如果有th,但是没有join,主线程会很快结束,但是th2因为还有一个非daemon未结束,所以不会很快结束,而一直等到th结束才结束
如果没有setDaemon,则th不影响th2
==================
线程的同步
当多个线程同时对一个对象进行操作,就有可能发生问题,这时就要用线程同步来解决
考虑下面的例子
class SychronizedTest
{
 public static void main(String[] args)
 {
  final Student stu = new Student();
  Thread setNameAndNumth1 = new Thread( new Runnable(){
   public void run(){
    while(true){
     synchronized(stu){
      stu.setNameAndNum("john","jj");
     }
    }
   }
  });
  Thread setNameAndNumth2 = new Thread( new Runnable(){
   public void run(){
    while(true){
     //synchronized(stu){
      stu.setNameAndNum("kate","kk");
     //}
    }
   }
  });
  setNameAndNumth1.start();
  setNameAndNumth2.start();
  System.out.println("test started:");
 }
}
class Student{
 private String name;
 private String id;
 private int count = 0;
 public /*synchronized*/ void setNameAndNum(String name,String id){
//  synchronized(this){
   this.name = name;
   this.id = id;
   count++;
   if(!check())
    System.out.println( count + " unmatched name and id: "+name+" "+id);
//  }
 }
 private boolean check(){
  return name.charAt(0) == id.charAt(0);
 }
}
在这个例子中,Student类有两个属性.
有两个线程,它们修改同一个Student类的实例,然后检查修改后的这个实例的两个属性符不符合要求(判断两个属性的第一个字符是否一样)
如果不符合要求,则在控制台输出语句,否则不输出
例子中有三部分注释,每一部分说明了一种同步方式
最上面方式使Student类的方法都按同步的方式执行
第二种通过synchronized关键字,使单一一个方法,而不是全部方法按同步的方式执行
第三种只是一个方法里的某一部分按同步的方法执行(虽然在这个例子里,方法的整个方法体都被括起来了)
====================================
最后附上经典的生者消费者程序
class WaitNotifyTest
{
 public static void main(String[] args)
 {
  Clerk clerk = new Clerk();
  Producer producer = new Producer(clerk);
  Consumer consumer = new Consumer(clerk);
  Thread producerThread = new Thread(producer);
  Thread consumerThread = new Thread(consumer);
  producerThread.start();
  consumerThread.start();
 }
}
class Producer implements Runnable{
 Clerk clerk;
 Producer(Clerk clerk){
  this.clerk = clerk;
 }
 public void run(){
  System.out.println("producer starts producing product " );
  for(int i=0; i<10; i++){
   try{
    Thread.sleep( (int)(Math.random()*3000) );
   }catch(InterruptedException e){
    e.printStackTrace();
   }
   clerk.setProduct(i);
//   System.out.println("producer is producing product " + i);
   
  }
 }
}
class Consumer implements Runnable{
 Clerk clerk;
 Consumer(Clerk clerk){
  this.clerk = clerk;
 }
 public void run(){
  System.out.println("consumer starts consuming product " );
  for(int i=0; i<10; i++){
   try{
    Thread.sleep( (int)(Math.random()*3000) );
   }catch(InterruptedException e){
    e.printStackTrace();
   }
   clerk.getProduct();
//   System.out.println("consumer is consuming product "+ i);
   
  }
 }
}
class Clerk{
 int product = -1;
 public synchronized void setProduct(int product){
  if( this.product != -1  ){
   try{  
     wait();
    }catch(InterruptedException e){
     e.printStackTrace();
    }
  }
  this.product = product;
  System.out.println("producer is producing product " + product);
  notify();
 }
 public synchronized void getProduct(){
  if( product == -1 ){
   try{
    wait();
   }catch(InterruptedException e){
    e.printStackTrace();
   }
  }
  System.out.println("consumer is consuming product "+ product);
  this.product = -1;
  notify();
 }

Feedback

# re: java线程简单介绍[zz]  回复  更多评论   

2009-04-09 20:56 by huxianbao
太有用了,呵呵

# re: java线程简单介绍[zz]  回复  更多评论   

2009-04-09 22:56 by huxianbao
最后一个生产者-消费者程序真的是太经典了
呵呵

只有注册用户登录后才能发表评论。


网站导航: