posts - 37, comments - 8, trackbacks - 0, articles - 0

java基础:关于线程

Posted on 2008-08-02 11:10 梦与桥 阅读(395) 评论(1)  编辑  收藏 所属分类: java基础

1、作用:使java应用程序同时完成多项任务,当其一个线程被阻塞时,只有那个被阻塞的线程暂停,所有其他线程继续执行。
2、概念:一个java程序可以包含多个线程,每个线程具有部分程序功能,能与其他线程同时执行,这种能力称为多线程。
3、线程只是在系统层被实现,核心编程语言需要一个特定的编程接口来实现。在java中,创建线程的方法有两种,其一是继承Thread类,其二是实现Runnable接口。

继承Thread类实例:
class MyThread extends Thread
{
 int count=1,num;static int COUNT=1;
 MyThread(int num)
 {
  this.num=num;
  System.out.println("创建线程"+num);
 }
 public void run()
 {
  while(true)
  {
   System.out.println("线程"+num+"统计:"+count+";总统计:"+(COUNT++));
   if((++count)>6)
    return;
  }
 }
}
public class Test
{
 public static void main(String args[])
 {
  for(int i=0;i<5;i++)
   new MyThread(i).start();
 }
}

实现Runnable接口实例:
class MyThread implements Runnable
{
 int count=1,num;static int COUNT=1;
 MyThread(int num)
 {
  this.num=num;
  System.out.println("创建线程"+num);
 }
 public void run()  //覆盖run()方法
 {
  while(true)
  {
   System.out.println("线程"+num+"统计:"+count+";总统计:"+(COUNT++));
   if((++count)>6)
    return;
  }
 }
}
public class Test
{
 public static void main(String args[])
 {
  //构造线程过程:Runnable target=new MyThread();
 // 构造线程过程续:Thread myThread=new Thread(taget);
  for(int i=0;i<5;i++)
   new Thread(new MyThread(i)).start();//Thread的构造函数实现之
 }
}

两种创建线程试方式的比较:
            §实现Runnable的优点:java的单一继承机制,使用户只能采用实现Runnable方法。
            §继承Thread的优点:当一个run()方法体现在继承Thread类的类中,用this指向实际控制运行的Thread实例,不需要如下控制:T hread.currentThread().jion(),而可以简单地写为:jion()。
            §使用 Runnable 接口来实现多线程使得我们能够在一个类中包容所有的代码,有利于封装,它的缺点在于,我们只能使用一套代码,若想创建多个线程并使各个线程执行不同的代码,则仍必须额外创建类,如果这样的话,在大多数情况下也许还不如直接用多个类分别继承 Thread 来得紧凑。
4、线程生命周期基本状态图:

一个Thread对象在它的生命周期中会处于以下几种状态:
        §新建状态(New Thread):线程已创建、实例化完毕,还未执行方法体run()以启动该线程。
        §就绪状态/可运行状态(Runnable):已调用start方法,为该线程完成登记工作和分配资源工作。可以用isAlive()方法识别一个线程是否处于runnable状态,若是返回true,否则返回false。
        §运行状态(Running):线程调度器为其分配了CPU时间,处于运行状态。
        §阻塞/挂起状态(Wait/Block):等待某个事件发生,一旦发生就离开该状态,进入Runnable状态。通常在调用sleep或wait方法进入该状态,I/O阻塞时也可进入该状态,或发生在多线程同步访问时,线程试图锁住已被另一个线程锁住的对象。
        §终止状态(Dead):run方法执行完毕,或非预期的异常发生导致run方法终止,使线程死亡,此时不可重新启动,与普通对象没有区别。

 5、一个多线程的实例:
class NewThread implements Runnable
{
 String name;
 Thread t;
 NewThread(String name)
 {
  this.name=name;
  t=new Thread(this,name);
  System.out.println("New thread:"+t);
  t.start();
 }
 public void run()
 {
  try
  {
   for(int i=3;i>0;i--)
    Thread.sleep(1000);//使一个线程暂停执行一段时间
  }
  catch (InterruptedException e)
  {
   System.out.println(name+"Interrupted");
  }
  System.out.println(name+"   exting.");
 }
}
public class Test
{
 public static void main(String args[])
 {
  NewThread nt1=new NewThread("First");
  NewThread nt2=new NewThread("Second");
  NewThread nt3=new NewThread("Third");
  //isAlive()方法用来测试其调用的线程是否仍在运行
  System.out.println("IsAlive(First):"+nt1.t.isAlive());
  System.out.println("IsAlive(Second):"+nt2.t.isAlive());
  System.out.println("IsAlive(Third):"+nt3.t.isAlive());
  try
  {
   System.out.println("Waiting for threads to finish.");
   //等待调用jion()的线程直到结束语
   nt1.t.join();
   nt2.t.join();
   nt3.t.join();
  }
  catch (InterruptedException e)
  {
   System.out.println("Main thread Interrupted");
  }
  //isAlive()方法用来测试其调用的线程是否仍在运行
  System.out.println("IsAlive(First):"+nt1.t.isAlive());
  System.out.println("IsAlive(Second):"+nt2.t.isAlive());
  System.out.println("IsAlive(Third):"+nt3.t.isAlive());
  System.out.println("Main thread exiting.");
 }
}
运行结果:

本例子实现了主线程最后结束,方法是子线程调用join()方法,让主线程等待其结束。

6、一个故事及和这个故事有关的线程问题:
故事:一男仙一女妖,偶然邂逅,真情相生,从此缠绵一处,不误正业。仙的上司听说后,非常恼火,上告玉帝,玉帝授权给他,让他惩治这一对仙妖冤家。他一直在想如何惩治时,一日到牢中发现,女妖正用勺子喂男仙,监狱的饭菜很差,但这一对其乐融融。他冷然一笑,走出牢房,对技术员说:“你给我编写一个程序,置入他们脑子里面,让一个永远不停地喂,一个永远不停地吃。”技术员眨了一会眼睛,“这个有两个问题,一是喂完了一勺子后,要停下来去取,这要男仙去等;在男仙嘴中塞满没有咽到肚里时,举起勺子的女妖要等,所以……”“这是你的事,你自己看着办。”技术员眨了一下眼睛退下,回到办公室,偶一思索,打开电脑,写出如下程序:

class Food
{
 int n;
 //标志,为false不允许咬,为true允许咬
 boolean blnValue=false;
 synchronized int get()
 {
  try
  {//如果没有食物,男仙等待
   wait();
  }
  catch (InterruptedException e)
  {
   System.out.println("InterruptedException caught");
  }
  //开吃,同时告诉女妖要盛饭了
  System.out.println("Got:"+n);
  blnValue=false;
  notify();
  return n;
 }
 synchronized void put(int n)
 {
  if(blnValue)
   try
   {//如果还没吃完,女妖等待
    wait();
   }
   catch (InterruptedException e)
   {
    System.out.println("InterruptedException caught");
   }
   //去取食物,同时告诉男仙
   this.n=n;
   blnValue=true;
   System.out.println("Put: "+n);
   notify();
 }
}
class Immortal implements Runnable
{
 Food f;
 Immortal(Food f)
 {
  this.f=f;
  new Thread(this,"Immortal").start();
 }
 public void run()
 {
  while(true)
  {
   f.get();
  }
 }

}
class Goblin implements Runnable
{
 Food f;
 Goblin(Food f)
 {
  this.f=f;
  new Thread(this,"Goblin").start();
 }
 public void run()
 {
  int i=1;
  while(true)
  {
   f.put(i++);
  }
 }
}
class Test
{
 public static void main(String args[])
 {
  Food f=new Food();
  new Immortal(f);
  new Goblin(f);
  System.out.println("问世间情为何物,叫人喂而不倦,吃而不倦:");
 }
}

技术员拿着程序去见上司,上司让它运行一遍,他运行之。上司点了点头,从抽屉里拿出一叠钞票,递给他说:“这是你的特别奖金,但是我要告诉你这不是因你的程序而发——这个程序我似曾相识啊,是因为你的这句:‘问世间情为何物,叫人喂而不倦,吃而不倦。’真是妙极了,是一种无耻的幸灾乐祸者,最想吟上800遍的啊。真希望,他们你喂我吃时,围着一圈人高唱这句啊。”“你说,这段程序你似曾相识?”“是啊,我也在学JAVA啊,挺好玩的嘛,线程我刚学了没多久。”
出了上司的办公室,技术员的衣服都湿了一片,回去后想了很久,第二天辞了职。当别人问及原因,他说:“偶在这压力太大,已经无法承受。”在一片惋惜中他离开了仙界,终于一次在酒后他说:“唉,我的那个上司没有人性啊,我怕。”“去,瞧你说,仙哪有人性,仙有仙品。”“那他是没有仙品了,反正是一种该有的东西他没有。”

7、百兽之王大宴宾客及线程优先级问题
百兽之王,偶逢佳运,得一至宝,欣喜若狂,于是大宴宾客,以示庆贺。设宴当日,高朋满座,良友如云,大家举杯相碰,其声清脆。百兽之王听之,捻须而笑。忽然一迎宾者慌张跑来,“报告大王,不好了,一群黑压压的飞虫正往这边飞来。”“今日来者均为客,奏乐欢迎。”“来得太多了,怕我把全部的食物拿出来,也不够招待他们的。”“奶奶个熊的,真是传说中的乞丐飞团,待我察看一下。”
百兽之王来到门外,搭眼一瞧,颜有所失,转首对狐狸说:“这个事情你去处理。”“是,大王。”狐狸答应之后,眼睛咕噜一转,计上心来,拿出手机来。
“喂,老兄,最近忙什么呢?”
“鼓捣JAVA啊。”
“功力有大增吧?”
“还好了,嘛事啊?”
“我有个问题,想请你帮个忙?”
“老朋友了,好说,不过,我有很长时间没有喝过酒了。”
“哈哈,放心吧,今天我们大王大宴宾客,款待贵宾的十瓶酒有你一瓶。”
“两瓶吧。”
“你TMD的真厉害,好吧,但你可得保证我们大王满意。”
“皆大欢喜,说吧,什么事?”狐狸便把大王给他的任务,添上自己的考虑说了一遍。很快,他的朋友,用java写出了一个程序,在大门的内嵌电脑上运行之。狐狸便对着那群飞虫说:“蜜蜂们,蝴蝶们,你们好,欢迎你们来做客。今天人这么多,这么热闹,我们不如做个游戏。就是,当我喊开始的时候,你们就从这个大门往里飞,一段时间,大门会自动关闭。然后,在大门里的,我们招待,在大门外的请便。”
随着狐狸的一声开始,蜜蜂们,蝴蝶们就匆匆往里飞。大门关上之后,根据统计的蜜蜂、蝴蝶数量,摆桌开宴。

宴毕,皆大欢喜,狐狸的朋友也得到两瓶好酒。我闻听此事,去访狐狸的这位朋友,想看一下他的那个程序。他看了我一会,在键盘上调了一通,写了一些代码,要了我的U盘,保存到上面,递给我说:“回去,好好看看这个。”
回来后,我打开那个程序段,原来是有关线程优先级问题的一个小程序:
class Animal implements Runnable
{
 int count=0;
 Thread t;
 private volatile boolean running=true;
 public Animal(int p)
 {
  t=new Thread(this);
  t.setPriority(p);
 }
 public void run()
 {
  while(running)
  {
   count++;
  }
 }
 public void stop()
 {
  running=false;
 }
 public void start()
 {
  t.start();
 }
}
public class Test
{
 public static void main(String args[])
 {
  Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
  Animal bee=new Animal(Thread.NORM_PRIORITY+2);
  Animal butterfly=new Animal(4);
  bee.start();
  butterfly.start();
  try
  {
   Thread.sleep(50000);
  }
  catch (InterruptedException e)
  {
   System.out.println("Main thread interrupted.");
  }
  bee.stop();
  butterfly.stop();
  try
  {
   bee.t.join();
   butterfly.t.join();
  }
  catch (InterruptedException e)
  {
   System.out.println("InterruptedException caught");
  }
  System.out.println("关门>>>>>>");
  System.out.println("飞来蜜蜂"+bee.count+"只.");
  System.out.println("飞来蝴蝶"+butterfly.count+"只.");
 }
}


8、线程同步和死锁
 当两个或更多线程需要访问同一个共享资源时,须用某种方式来确保资源某一时刻只被一个线程使用,达到这个目的方式称之为同步。java中引入了互斥锁的概念,每个对象都对应于一个可称为“互斥锁”的标记,这个标记保证在任一时刻,只能有一个访问该对象。关键字synchronized用来与对象的互斥锁联系,实现同步。凡有带有synchronized关键字的方法或者代码段,系统运行时只会为之分配一个线程。
实例:

class TThread extends Thread
{
 private int sum=0;
 String str=new String("");
 public void run()
 {
  while(true)
  {
   synchronized(str)
   {
    if(sum<=10)
    {
     try
     {
      Thread.sleep(10);
     }
     catch (Exception e)
     {
      e.printStackTrace();
     }
     System.out.println(Thread.currentThread().getName()+"now sum is:"+sum++);
    }
   }
  }
 }
}
public class Test
{
 public static void main(String[] args)
 {
  TThread t=new TThread();
  Thread t1=new Thread(t);
  Thread t2=new Thread(t);
  Thread t3=new Thread(t);
  Thread t4=new Thread(t);

  t1.start();
  t2.start();
  t3.start();
  t4.start();
 }
}

注意: java语言中提供了wait()和notify()两个方法,这两个方法不能被重载,并且只能在同步方法中被调用。如果程序中有多个线程竞争多个资源,可能发生死锁。当一个线程等待由另一个线程持有的锁,而后者正在等待已被第一个线程持有的锁时,就会发生死锁。Java技术不检测也不试图避免这种情况,因而保证不发生死锁是程序员的责任。一个通用的法则:决定获取锁的次序并始终遵照这个次序,按照与获取相反的次序释放锁。

Feedback

# re: java基础:关于线程[未登录]  回复  更多评论   

2009-07-25 02:42 by ^_^
帅!!!!!!!!!!!!!!!!!!!
我喜欢

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


网站导航: