第七章、多线程
第一节、Java中的多线程
一、什么是线程?
和其他多数计算机语言不同,Java内置多线程编程(multithreaded programming)。多线程程序包含两条或两条以上并发运行的部分。程序中每个这样的部分都叫做一个线程(thr
ead),每条线程都有独立的执行路径。多线程是多任务处理的一种特殊形式。
多任务处理有两种截然不同的类型:基于进程的和基于线程的。 进程(process)本质上是一个执行的程序。因此,基于多进程的多任务处理的特点是允许你的计算机同时运行两个或更多的程序。在这种多任务处理中,程序是调度程序所分派的最小代码单位。 在基于线程的多任务处理环境中,线程是最小的执行单位。这意味着一个程序可以同时执行两个或多个任务的功能。
单线程的程序由于只有一个线程,所以如果该线程因为等待资源时阻塞(block,挂起执行),那么整个程序就停止了运行。在Java多线程的程序中,如果出现一个线程阻塞,那么只有该线程暂停或挂起,而其他线程可继续运行,除非所有线程都阻塞,否则不会导致程序停止,这样就能更高效的利用CPU资源,使程序执行更为高效。
线程存在几种状态: running 正在运行
suspend 挂起 被挂起的线程可以resume(恢复)
block 阻塞
terminate 终止
二、线程调度和优先级
Java给每个线程安排优先级以决定与其他线程比较时该如何对待该线程。优先级最高的线程是Java正在运行的线程,其他所有线程必须等待。如果多个线程有同样的最高优先级,则Java会在它们之间切换。线程优先级的数值在Thread.MIN_PRIORITY和Thread.MAX_PRIORITY之间。默认优先级Thread.NORM_PRIORITY的数值是这两者中间的数。新的线程拥有与产生它们的线程同样的优先级。
你能使用setPriority()来显式地设置线程优先级,也可以用getPriority()来获得线程的优先级。
三、创建线程
1.Java中定义了两种创建线程的方法:
* 实现Runnable接口
(Better object=oriented design, Single inheritance , Consistency)
* 继承Thread 类
(Simpler code)
(1) 实现Runnable接口
创建线程的最简单的方法就是创建一个实现Runnable接口的类,然后将该类的实例对象传给Thread构造函数,Thread对象指定Runnable对象的run()方法是线程的主体。为实现Runnable接口,一个类仅需实现一个run()的简单方法(即覆盖run方法),该方法声明如下:
public void run()
在run()方法中你可以定义代码来构建新的线程。在run()方法中,能够像主线程那样调用其他方法,引用其他类,声明变量。run()方法在程序中确立了另一个并发的线程执行入口。当run()方法返回时,该线程结束。在实现了Runnable接口的类中(即实现了run方法),你可以在该类内部实例化一个Thread类的对象,并将当前Runnable对象传给Thread构造函数。建立一个新的线程后,它并不运行直到调用了它的start()方法,该方法在Thread类中定义,本质上,start()执行的是一个对run()的调用。start()方法声明如下: void start()
实例分析:
package Examples;
class MyRunThread implements Runnable{
Thread t;
MyRunThread(){
//Create a new thread
t=new Thread(this,"Demo Thread"); // this指明当前类的对象
System.out.println("Child thread: "+t);
t.start(); // 在线程的构造器中调用start()方法,当使用new运行算符
// 创建这个线程的一个实例对象时,该对象就会自动运行。
}
//This is the entry point for the new thread
public void run(){
try{
for(int i=5;i>0;i--){
System.out.println("Child thread: "+ i);
Thread.sleep(500);
}
}catch(InterruptedException e){
System.out.println("Child thread interrupted!");
}
System.out.println("Exit child thread!");
}
}
class ThreadRunnableDemo{
public static void main(String[] args){
new MyRunThread();
//当MyRunThread类的构造器中没有调用start()方法时,可以用一下语句实现// 相同的功能:
// (new MyRunThread()).t.start();
try{
for(int i=5;i>0;i--){
System.out.println("Main thread: "+i);
Thread.sleep(1000);
}
}catch(InterruptedException e){
System.out.println("Main thread interrupted!");
}
System.out.println("Main thread exiting.");
}
}
(2) 继承Thread类
当一个类继承Thread类时,它必须覆盖(override)run()方法,这个run方法是新线程的入口,也必须通过调用start()方法来启动新线程。Thread类常用的几个构造器:
public Thread(); //默认无参数的构造器
public Thread(String name); //传入字符串设置线程名称
public Thread(Runnable target) //传入Runnable对象引用,指明在此对象中你想
//要新的线程调用run()方法
public Thread(Runnable target, String name) // 同上,并设置了线程名称
实例分析:
只需对上面例子作两处更改即可:
第一,更改 “class MyRunThread implements Runnable”为
class MyRunThread extends Thread
第二,更改构造器内代码为
MyRunThread(){
super("Demo Thread"); //由于MyRunThread是继承Thread类的,
// 本身是Thread类型的一个对象,故可使用super调用超类的构造函数
System.out.println("Child thread: "+this);
start(); // 直接调用继承于超类的start()方法。
}
2.主线程
当Java程序启动时,一个线程立刻运行,该线程通常叫做程序的主线程(main thread),因为它是程序开始时就执行的,主线程的重要性体现在两方面:
* 它是产生其他子线程的线程。 (即其他线程创建时具有和主线程相同的优先级)
* 通常它必须最后完成执行,因为它执行各种关闭动作。
尽管主线程在程序启动时自动创建,但它可以由一个Thread对象控制。为此,你必须调用方法currentThread()获得它的一个引用,currentThread()是Thread类的共有静态成员,它的通常形式如下:
static Thread currentThread()
该方法返回一个调用它的线程的引用。一旦你获得主线程的引用,你就可以像控制其他线程那样控制主线程。例如: Thread t = Thread.currentThread(); // 获得主线程的一个引用
3.使用isAlive()和join()方法
在有多个线程的情况下,通常我们希望主线程最后结束。isAlive()方法可以判断一个线程是否结束,它的通常形式如下:
final boolean isAlive()
而join()方法的调用可以确保主线程最后结束,它的形式如下:
final void join() throws InterruptedException
实例分析:
package Examples;
class MultiThread implements Runnable{
Thread t;
String name;
int time;
MultiThread(String threadName,int sleepTime){ //传入参数设置线程名称和休眠时间
name=threadName;
time=sleepTime;
t=new Thread(this,name);
System.out.println("Child Thread : "+t);
t.start();
}
public void run(){
try{
for(int i=5;i>0;i--){
System.out.println(name+ " : "+ i);
Thread.sleep(time);
}
}catch(InterruptedException e){
System.out.println(name+" interrupted!");
}
System.out.println(name + " exiting!");
}
}
public class MultiThreadDemo{
public static void main(String[] args){
MultiThread mt1=new MultiThread("One",1000);
MultiThread mt2=new MultiThread("Two",500);
MultiThread mt3=new MultiThread("Three",800);
System.out.println("Thread One is alive: "+mt1.t.isAlive());
System.out.println("Thread Two is alive: "+mt2.t.isAlive());
System.out.println("Thread Three is alive: "+mt3.t.isAlive());
try{
System.out.println("Waiting for sub thread to finish.");
mt1.t.join();
mt2.t.join();
mt3.t.join();
// 调用join()方法后,会确保所有调用join()方法的子线程执行完毕后
// 才执行下面的代码
System.out.println("Thread One is alive: "+mt1.t.isAlive());
System.out.println("Thread Two is alive: "+mt2.t.isAlive());
System.out.println("Thread Three is alive: "+mt3.t.isAlive());
for(int i=5;i>0;i--){
System.out.println("Main thread : "+i);
Thread.sleep(400);
}
}catch(InterruptedException e){
System.out.println("Main thead interrupted!");
}
}
}