Java第二十章
一.创建线程
1.继承Thread类
Thread类是java.lang 包中的一个类,从这个类中实例化的对象代表线程,程序员启动一个新线程需要建立Thread实例。Thread类中常用的两个构造方法如下:
public Thread()://创建一个新的线程对象。
public Thread(String threadName)://创建一个名称为threadName的线程对象
//继承Thread类创建一个新的线程的语法如下:
public class ThreadTest extends Thread{
}
例1.
2.实现Runnable接口
到目前为止,线程都是通过扩展Thread 类来创建的,如果程序员需要继承其他类(非Thread类),而且还要使当前类实现多线程,那么可以通过 Runnable 接口来实现。例如,一个扩展JFrame类的GU程序不可能再继承Thread类,因为Java语言中不支持多继承,这时该类就需要实现Runmable接口使其具有使用线程的功能。实现Runnable接口的语法如下:
public class Thread extends Object implements Runnable
实现 Runnable 接口的程序会创建一个 Thread 对象,并将 Runnable 对象与 Thread 对象相关联,Thread类中有以下两个构造方法:
public Thread(Runnable target)
public Thread(Runnable target,String name)
例2.
二.线程的生命周期
线程具有生命周期,其中包含 7 种状态,分别为出生状态、就绪状态、运行状态、等待状态、休眠状态、阻塞状态和死亡状态。出生状态就是线程被创建时处于的状态,在用户使用该线程实例调用start()方法之前线程都处于出生状态;当用户调用start()方法后,线程处于就绪状态(又被称为可执行状态);当线程得到系统资源后就进入运行状态。
一旦线程进入可执行状态,它会在就绪与运行状态下转换,同时也有可能进入等待、休眠、阻塞或死亡状态。当处于运行状态下的线程调用 Thread 类中的 wait0方法时,该线程便进入等待状态,进入等待状态的线程必须调用Thread类中的notify()方法才能被唤醒,而调用otifyAll()方法可将所有于等待状态下的线程唤醒;当线程调用 Thread 类中的 sleep()方法时,则会进入休眠状态。如果一个线程在运行状态下发出输入/输出请求,该线程将进入阻塞状态,在其等待输入/输出结束时线程进入就绪状态,对于阻塞的线程来说,即使系统资源空闲,线程依然不能回到运行状态。当线程的 run()方法执行完毕时,线程进入死亡状态。
三.操作线程的方法
1.线程的休眠
一种能控制线程行为的方法是调用 sleep()方法,sleep()方法需要一个参数用于指定该线程休眠的时间,该时间以毫秒为单位。在前面的实例中,已经演示过 sleep()方法,它通常是在 run()方法内的循环中被使用。sleep()方法的语法如下:
try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
例3.
2.线程的加入
如果当前某程序为多线程程序,假如存在一个线程A,现在需要插入线程 B,并要求线程B先执行完毕,然后再继续执行线程A,此时可以使用Thread类中的join()方法来完成。这就好比此时读者正在看电视,突然有人上门收水费,读者必须付完水费后才能继续看电视。
当某个线程使用 join()方法加入另外一个线程时,另一个线程会等待该线程执行完毕后再继续执行。
例4.
3.线程的中断
以往有的时候会使用 stop()方法停止线程,但当前版本的JDK 早已废除了 stop()方法,不建议使用stop()方法来停止一个线程的运行。现在提倡在run()方法中使用无限循环的形式,然后使用一个布尔型标记控制循环的停止。
例5.
4.线程的礼让
Thread 类中提供了一种礼让方法,使用 yield()方法表示,它只是给当前正处于运行状态的线程一个提醒,告知它可以将资源礼让给其他线程,但这仅是一种暗示,没有任何一种机制保证当前线程会将资源礼让。
四.线程的优先级
Thread 类中包含的成员变量代表了线程的某些优先级,如 Thread.MIN_PRIORITY(常数1)Thread.MAX_PRIORITY(常数10)、Thread.NORM_PRIORITY(常数5)。其中每个线程的优先级都在Thread.MIN_PRIORITY~Thread.MAX_PRIORITY,在默认情况下其优先级都是 Thread.NORM_PRIORITY。每个新产生的线程都继承了父线程的优先级。
例6.
五.线程同步
1.线程安全
实际开发中,使用多线程程序的情况很多,如银行排号系统、火车站售票系统等。这种多线程的程序通常会发生问题,以火车站售票系统为例,在代码中判断当前票数是否大于 0,如果大于0则执行将该票出售给乘客的功能,但当两个线程同时访问这段代码时(假如这时只剩下一张票),第一个线程将票售出,与此同时第二个线程也已经执行完成判断是否有票的操作,并得出票数大于 0的结论,于是它也执行售出操作,这样就会产生负数。所以,在编写多线程程序时,应该考虑到线程安全问题.实质上线程安全问题来源于两个线程同时存取单一对象的数据。
2.线程同步机制
同步块
Java 中提供了同步机制,可以有效地防止资源冲突。同步机制使用 synchronized 关键字,使用该关键字包含的代码块称为同步块,也称为临界区,语法如下:
synchronized (Object){
}
例7.
同步方法
同步方法就是在方法前面用synchronized关键字修饰的方法,其语法如下:
synchronized void f(){}
当某个对象调用了同步方法时,该对象上的其他同步方法必须等待该同步方法执行完毕后才能被执行。必须将每个能访问共享资源的方法修饰为synchronized,否则就会出错。