第九章 线程html
9.1 定义、实例化并启动线程java
考试目标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 实例化线程spa
每一个执行线程都是做为Thread类的一个实例开始的。线程
对于扩展Thread类而定义的线程实例化方式以下:设计
MyThread t = new MyThread();
对于实现Runnable接口而定义的线程实例化方式以下:code
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()