第九章 线程
9.1 定义、实例化并启动线程
考试目标4.1 使用java.lang.Thread和java.lang.Runnable编写代码,定义、实例化并启动新线程。
9.1.1 定义线程
扩展java.lang.Thread类,重写run()方法。
class MyThread extends Thread{ public void run(){ System.out.println("Important job running in MyThread"); } }
实现java.lang.Runnable,实现run()方法。
class MyRunnable implements Runnable{ public void run(){ System.out.println("Important job running in MyRunnable"); } }
9.1.2 实例化线程
每个执行线程都是作为Thread类的一个实例开始的。
对于扩展Thread类而定义的线程实例化方式如下:
MyThread t = new MyThread();
对于实现Runnable接口而定义的线程实例化方式如下:
MyRunnable r = new MyRunnable(); Thread t = new Thread(r);
t.start();
在调用start()方法后,发生:
启动新的执行线程(具有新的调用栈)。
线程从新状态转到可运行状态(runnable state)。
当线程获得执行机会时,会运行它的目标run()方法。
Thread.currentThread()用来获取当前线程引用。
Thread.getName()用来获得线程的名字。
启动并运行多个线程:
每个线程都会启动,而且每个线程都将运行到结束。但是顺序,优先没有绝对保证。
当线程的目标run()方法结束时,该线程就完成了。死线程不能再次调用start()方法。
只要线程已经启动过,它就永远不能再次启动。
线程调度器:
可运行线程编程运行中线程的顺序是没有保证的。
java.lang.Thread类中控制(影响)线程的方法:
public static void sleep(long millis) throws InterruptedException public static void yield() public final void join() throws InterruptedException public final void setPriority(int newPriority) //默认是5,值越大,优先越高 1-10
java.lang.Object类中控制(影响)线程的方法:
public final void wait() throws InterruptedException public final void notify() //唤醒单个线程 public final void notifyAll() //唤醒所有线程
9.2 线程状态与转变
考试目标4.2 识别线程能够位于哪些状态,并确定线程能从一种状态转变成另一种状态的方式。
9.2.1 线程状态
新状态--new
可运行状态--runable
运行中状态--running
等待/阻塞/睡眠状态--waiting/blocked/sleeping
死状态--dead
9.2.2 阻止线程执行
一个线程被踢出“运行中”状态,而不是被送回“可运行”或“死”状态。
即:睡眠,等待,因为需要对象的锁而被阻塞。
9.2.3 睡眠
Thread的两个静态方法:
public static void sleep(long millis) throws InterruptedException //millis是毫秒
public static void sleep(long millis,int nanos) throws InterruptedException //nanos是纳秒
9.2.4 线程优先级和yield()
调度器在优先级上是没有保证的,主要是看它“喜欢。。还是不喜欢”,真够无奈的。
设置线程的优先级
t.setPriority(int i);
yield()方法
Thread的静态方法yield(),让当前的“运行中”线程回到“可运行”状态,让步给具有相同优先级的其他“可运行”线程,但这是没有任何保证的。
join()方法
Thread的非静态方法join()让当前线程加入到引用的线程尾部,这意味着调用方法的线程完成(死状态)之前,主线程不会变为可运行的。
public final void join() //要一直等待该线程结束 throws InterruptedException
public final void join(long millis) //millis为0表示要一直等下去 throws InterruptedException
public final void join(long millis, int nanos) throws InterruptedException
9.3 同步代码
考试目标4.3 给定一个场景,编写代码,恰当地使用对象锁定来保护静态变量或实例变量,使它们不出险并发访问问题。
9.3.1 同步和锁 synchronized
静态方法能否同步
可以,静态代码块也可以。例如:
public static synchronized int getCount(){ return count; } public static int getCount(){ //注意synchronized关键字后面括号里的内容:即要锁的类或对象 synchronized(MyClass.class){ return count; } }
如果线程不能获得锁会怎么样?
会阻塞,等锁释放。
何时需要同步?
书云:对于复杂的情况“如果你不想它的话,你的生命就会更长、更愉快。真的如此,我们没有撒谎。”
线程安全类
StringBuffer等
9.3.2 线程死锁
9.4 线程交互
考试目标4.4 给定一个场景,编写代码,恰当地使用wait()、notify()和notifyAll()方法。
必须在同步方法内调用wait()、notify()和notifyAll()方法!线程不能调用对象上的等待或通知方法,除非它拥有该对象的锁。
9.4.1 当多个线程等待时使用notifyAll()
在循环中使用wait()