java线程练习题及答案 下载本文

线程与线程类

1 线程的概念

线程的概念来源于计算机的操作系统的进程的概念。进程是一个程序关于某个数据集的一次运行。也就是说,进程是运行中的程序,是程序的一次运行活动。

线程和进程的相似之处在于,线程和运行的程序都是单个顺序控制流。有些教材将线程称为轻量级进程(light weight process)。线程被看作是轻量级进程是因为它运行在一个程序的上下文内,并利用分配给程序的资源和环境。

作为单个顺序控制流,线程必须在运行的程序中得到自己运行的资源,如必须有自己的执行栈和程序计数器。线程内运行的代码只能在该上下文内。因此还有些教程将执行上下文(execution context)作为线程的同义词。

所有的程序员都熟悉顺序程序的编写,如我们编写的名称排序和求素数的程序就是顺序程序。顺序程序都有开始、执行序列和结束,在程序执行的任何时刻,只有一个执行点。线程(thread)则是进程中的一个单个的顺序控制流。单线程的概念很简单,如图1所示。

多线程(multi-thread)是指在单个的程序内可以同时运行多个不同的线程完成不同的任务,图2说明了一个程序中同时有两个线程运行。

一个线程 两个线程 图1 单线程程序示意图 图2 多线程程序示意图

有些程序中需要多个控制流并行执行。例如,

for(int i = 0; i < 100; i++)

System.out.println(\for(int j = 0; j < 100; j++ )

System.out.println(\上面的代码段中,在只支持单线程的语言中,前一个循环不执行完不可能执行第二个循环。要使两个循环同时执行,需要编写多线程的程序。

很多应用程序是用多线程实现的,如Hot Java Web浏览器就是多线程应用的例子。在Hot Java 浏览器中,你可以一边滚动屏幕,一边下载Applet或图像,可以同时播放动画和声音等。

2 Thread类和Runnable接口

多线程是一个程序中可以有多段代码同时运行,那么这些代码写在哪里,如何创建线程对象呢?

首先,我们来看Java语言实现多线程编程的类和接口。在java.lang包中定义了Runnable接口和Thread类。

Runnable接口中只定义了一个方法,它的格式为: ? public abstract void run()

这个方法要由实现了Runnable接口的类实现。Runnable对象称为可运行对象,一个线程的运行就是执行该对象的run()方法。

Thread类实现了Runnable接口,因此Thread对象也是可运行对象。同时Thread类也是线程类,该类的构造方法如下:

? public Thread()

? public Thread(Runnable target) ? public Thread(String name)

? public Thread(Runnable target, String name)

? public Thread(ThreadGroup group, Runnable target) ? public Thread(ThreadGroup group, String name)

? public Thread(ThreadGroup group, Runnable target, String name) target为线程运行的目标对象,即线程调用start()方法启动后运行那个对象的run()方法,该对象的类型为Runnable,若没有指定目标对象,则以当前类对象为目标对象;name为线程名,group指定线程属于哪个线程组(有关线程组的概念请参考9.6节)。

Thread类的常用方法有:

? public static Thread currentThread() 返回当前正在执行的线程对象的引用。 ? public void setName(String name) 设置线程名。 ? public String getName() 返回线程名。

? public static void sleep(long millis) throws InterruptedException

? public static void sleep(long millis, int nanos) throws InterruptedException

使当前正在执行的线程暂时停止执行指定的毫秒时间。指定时间过后,线程继续执行。该方法抛出InterruptedException异常,必须捕获。 ? public void run() 线程的线程体。

? public void start() 由JVM调用线程的run()方法,启动线程开始执行。 ? public void setDaemon(boolean on) 设置线程为Daemon线程。 ? public boolean isDaemon() 返回线程是否为Daemon线程。

? public static void yield() 使当前执行的线程暂停执行,允许其他线程执行。 ? public ThreadGroup getThreadGroup() 返回该线程所属的线程组对象。 ? public void interrupt() 中断当前线程。

? public boolean isAlive() 返回指定线程是否处于活动状态。

线程的创建

本节介绍如何创建和运行线程的两种方法。线程运行的代码就是实现了Runnable接口的类的run()方法或者是Thread类的子类的run()方法,因此构造线程体就有两种方法:

? 继承Thread类并覆盖它的run()方法;

? 实现Runnable接口并实现它的run()方法。 继承Thread类创建线程

通过继承Thread类,并覆盖run()方法,这时就可以用该类的实例作为线程的目标对象。下面的程序定义了SimpleThread类,它继承了Thread类并覆盖了run()方法。

程序SimpleThread.java

public class SimpleThread extends Thread{ public SimpleThread(String str){ super(str); }

public void run(){

for(int i=0; i<100; i++){

System.out.println(getName()+\ try{

sleep((int)(Math.random()*100)); }catch(InterruptedException e){} }

System.out.println(getName()+ \} }

_____________________________________________________________________________▃ SimpleThread类继承了Thread类,并覆盖了run()方法,该方法就是线程体。

程序 ThreadTest.java public class ThreadTest{

public static void main(String args[]){

Thread t1 = new SimpleThread(\ Thread t2 = new SimpleThread(\ t1.start(); t2.start(); } }

_____________________________________________________________________________▃ 在ThreadTest类的main()方法中创建了两个SimpleThread类的线程对象并调用线程类的start()方法启动线程。构造线程时没有指定目标对象,所以线程启动后执行本类的run()方法。

注意,实际上ThreadTest程序中有三个线程同时运行。请试着将下段代码加到main()方法中,分析程序运行结果。

for(int i=0; i<100; i++){

System.out.println(Thread.currentThread().getName()+\ try{

Thread.sleep((int)(Math.random()*500)); }catch(InterruptedException e){}

System.out.println(Thread.currentThread().getName()+ \ }

从上述代码执行结果可以看到,在应用程序的main()方法启动时,JVM就创建一个主线程,在主线程中可以创建其他线程。

再看下面的程序:

程序 MainThreadDemo.java

public class MainThreadDemo{

public static void main(String args[]){ Thread t = Thread.currentThread(); t.setName(\ System.out.println(t);

System.out.println(t.getName());

System.out.println(t.getThreadGroup().getName()); } }

_____________________________________________________________________________▃ 该程序输出结果为:

Thread[MyThread, 5, main] MyThread main

上述程序在main()方法中声明了一个Thread对象t,然后调用Thread类的静态方法currentThread()获得当前线程对象。然后重新设置该线程对象的名称,最后输出线程对象、线程组对象名和线程对象名。 实现Runnable接口创建线程

可以定义一个类实现Runnable接口,然后将该类对象作为线程的目标对象。实现Runnable接口就是实现run()方法。

下面程序通过实现Runnable接口构造线程体。 程序 ThreadTest.java

class T1 implements Runnable{ public void run(){

for(int i=0;i<15;i++)

System.out.println(\ } }

class T2 implements Runnable{ public void run(){

for(int j=0;j<15;j++)

System.out.println(\ } }

public class ThreadTest{

public static void main(String args[]){

Thread t1=new Thread(new T1(),\ Thread t2=new Thread(new T2(),\ t1.start(); t2.start(); } }

_____________________________________________________________________________▃

线程的状态与调度

1线程的生命周期

线程从创建、运行到结束总是处于下面五个状态之一:新建状态、就绪状态、运行状态、阻塞状态及死亡状态。线程的状态如图4所示:

新建状态 就绪状态 阻塞状态 运行状态 死亡状态 图4 线程的五种状态

下面以前面的Java小程序为例说明线程的状态: