JAVA多线程

来源:互联网 发布:淘宝法院拍卖网 编辑:程序博客网 时间:2024/06/08 07:39

JAVA多线程


1. 引言

  并发编程使我们可以将程序划分为多个分离的、独立的任务,通过使用多线程机制,这些独立任务重的每一个都将由执行线程来驱动。一个线程就是在进程中的一个单一的顺序控制流,因此单个进程可以拥有多个并发执行的任务。线程模型为编程带来了遍历,简化了在单一程序中同时交织在一起的多个操作的处理。在使用线程时,CPU将轮流给每个任务分配其占用时间。因此,多任务和多线程往往是使用多处理器系统的最合理方式。

2. 定义任务

  线程可以驱动任务,因此我们需要一种描述任务的方式,这种方式可以由Runnable接口提供。定义任务只需要实现Runnable接口并编写run()方法,使得该任务可以执行所需要的命令,例如:

class Taskclass implements Runnable{  public Taskclass(){}//构造函数  public void run(){}//重写run方法}

  当我们创建好了实现Runnable接口的类之后,我们便可以通过start函数运行指定的任务,例如:

public class threadTest{  public static void main(String[] args){    Taskclass task=new Taskclass();//实例化任务类    Thread thread=new thread(task);//创建执行指定任务的线程    thread.start();//开始执行线程  }}

  任务中run()方法指明了如何完成这个任务,Java虚拟机会在线程执行中自动调用这个方法,因此我们无需特意调用它。直接调用run()知识在同一个线程中执行该方法,而没有新线程被启用。

3. Thread类

  将Runnable对象转变为工作任务的传统方式是把它提交给一个Thread构造器,前文中的代码给出了如何使用Tread来驱动任务类。Thread构造器只需要一个Runnable对象,即public Thread(Runnable object)。调用Thread对象的start()方法为该线程执行必须的初始化操作,然后调用Runnable的run()方法,在这个新线程中启动该任务。
  Thread类中还包括了一些常用的操作线程的方法包括,sleep(long mills)使线程睡眠指定时间;yield()使线程暂定并执行允许执行其他线程;join()等待线程结束。下面给出具体的应用示范。

public class threadTest{  Runnable task1=new printChar('a',100);  Runnable task2=new pirntChar('b',100);  Runnable task3=new printNum(100);  //创建任务类  Thread thread1=new Thread(task1);  Thread thread2=new Thread(task2);  Thread thread3=new Thread(task3);  //创建线程  thread1.start();  thread2.start();  thread3.start();  //启动线程}class printChar implements Runnable{  char c;  int num;  public printChar(char c, int num){    this.c=c;    this.num=num;  }  public void run(){    for(int i=0;i<num;i++)      System.out.println(c);  }}class printNum inplements Runnable{  int num;  public printNun(int num){    this.num=num;  }  public void run(){    for(int i=0;i<num;i++)      System.out.println(i);  }}

  上述任务将在三条线程中输出字母a,b和顺序打印0-99数字,若对上述程序进行以下修改,则结果将会产生变化,例如在printNum类中修改run()方法,添加thread.yield()方法

public void run(){  for(int i=0;i<num;i++){    System.out.println(c);    thread.yield();    }}

  则输出则会变为,每打印一个数字后都会暂停printNum任务,因此最终结果来看每个数字后面都会紧跟一系列的字符,因为在printNum线程暂停时,打印字符的任务允许运行。
继续修改run()方法,在其中添加join()方法,例如:

public void run(){  Thread thread4=new Thread(thread4.start(new printChar('c', 40)));  try{    for(int i=0;i<num;i++){      System.out.println(i);      if(i==50) thread4.join();//当i为50时,暂定当前线程跳入thread4线程    }  }catch(InterruptedException ex){    ex.printStackTrace();  }}

  在run方法中创建了一个新线程thread4,在i的值上升为50时跳转至thread4,线程4打印字符40次。我们再次对run方法进行修改,添加了sleep方法,代码如下:

public void run(){  try{    for(int i=0;i<num;i++){      System.out.println(c);      if(i>=50) Thread.sleep(1);//当i大于等于50时,线程每输出一次字符则睡眠1毫秒    }  }catch(InterruptedException ex){}}

4. 小结

  当main()创建Thread对象时,它并没有捕获任何对这些对象的引用。在使用普通对象时,这对于垃圾回收来说是公平的,但是在使用thread时,情况则不同。每个thread都“注册”了自己,因此确实有一个对他的引用,而且在它的任务退出运行run()方法并死亡之前,我们无法清除它。因此,一个线程会创建一个单独的执行线程,在对start()调用完成之后,这个线程任然会存在。

0 0
原创粉丝点击