使用Thread类的子类创建线程写法,如:
public class SpeakElephant extends Thread {
public void run(){
...}
}
SpeakElephant xxx; //声明
xxx=new SpeakElephant(); //创建线程
直接使用Thread类创建线程写法:
public class Elephant (extends 某个特定类) implements (Runnable,...,...) {
public void run(){
...}
}
Thread xxx; //用Thread声明该线程
xxx=new Thread(implements Runnable接口所写的目标对象); //创建线程
编写Thread类的子类时需要重写 run() 方法,因为这个方法本身在父类没有任何操作语句
线程优先级分十个等级,从1(Thread.MIN_PRIORITY)到10(Thread.MAX_PRIORITY),默认是5(Thread.NORM_PRIORITY)
setPriority(int grade); //设置优先级 getPriority(int grade); //返回优先级
超出范围返回 IllegalArgumenException 异常
线程重复 start() 会发生 IllegalThreadStateException 异常。
线程在休眠时被打断,JVM就会抛出 InterruptedException 异常,sleep方法必须在try-catch语句中调用。
使用线程同步,方法使用sychronized修饰:
sychronized void fangfa(){ ... }
线程默认是非守护线程,非守护线程也称作用户线程,一个线程调用 void setDaemon(boolean on)方法可以将自己设置成一个守护(Daemon)线程:
Thread a=new Thread(); a.setDaemon(true);
//若想成为守护线程,必须在线程start之前设置
a.start();
对于调用了sleep()方法进入休眠状态的线程,可以调用interrupt() "吵醒"自己并重新排队等待cpu资源。
wait(),notify(),notifyAll()都是Object类中的final方法,被所有类继承且不允许重写的方法,不可以在非同步方法中使用以上三个方法,也就是对sleep()无效,而是对wait()有效。
对P327 注意项的思考:
因为张飞先start(),此时买票由于未能找回15块而需要继续买票,从 wait() 改为 Thread.sleep(3000) 后,张飞这个线程休眠三秒,然后醒来后 fiveAmount 仍然保持等于2,所以张飞这个线程就一直不满足条件,陷入了自己的 while 循环内,而此刻即使在循环内线程sleep了,JVM却还不能把CPU资源给李逵,因此李逵永远无法买票,不能凑够3张5块给张飞找钱,而且张飞在三秒后醒来还是买不了票,再次掉入 while 循环,然后又休眠,如此循环下去。
运行结果:
张飞继续买票
张飞靠边等...
//3s later
张飞继续买票
张飞靠边等...
......
--------------------------------------------------------------------------------------------------------------------------------------------------------
这是自己写的一个线程实验,发现很奇怪的是Joe这个线程第一次 sleep 的时候对他进行 interrupt 并不能有效唤醒,后面两次倒是可以正常唤醒,玄学!
class playTheCar {
public static void main(String Args[]) {
Home home = new Home();
home.setCarTime(0);
Thread Tom = new Thread(home);
Thread Joe = new Thread(home);
Tom.setName("Tom");
Joe.setName("Joe");
Tom.start();
Joe.start();
}
}
class Home implements Runnable {
int carTime = 0;
void setCarTime(int value) {
carTime = value;
}
public void run() {
if (Thread.currentThread().getName().equals("Tom")) {
play(1);
} else if (Thread.currentThread().getName().equals("Joe")) {
play(2);
}
}
public synchronized void play(int amount) {
if (Thread.currentThread().getName().equals("Tom")) {
for (int i = 1; i <= 3; i++) {
carTime+=amount;
System.out.println("Tom 玩第" + i + "次车子" + " carTime= " + carTime);
try {
System.out.println("等一秒别人帮他捡车子");
Thread.sleep(1000);
System.out.println("已经捡回来,继续玩");
} catch (InterruptedException e) {
}
}
}
else if (Thread.currentThread().getName().equals("Joe")) {
for (int i = 1; i <= 3; i++) {
carTime+=amount;
System.out.println("Joe 玩第" + i + "次车子" + " carTime= " + carTime);
try {
System.out.println("等五秒别人帮他捡车子");
Thread.sleep(5000);
System.out.println("已经捡回来,继续玩");
} catch (InterruptedException e) {
System.out.println("Joe不等别人帮他捡车了,自己自觉去捡车子");
}
Thread.currentThread().interrupt();
}
}
}
}
运行结果:
Tom 玩第1次车子 carTime= 1
等一秒别人帮他捡车子
已经捡回来,继续玩
Tom 玩第2次车子 carTime= 2
等一秒别人帮他捡车子
已经捡回来,继续玩
Tom 玩第3次车子 carTime= 3
等一秒别人帮他捡车子
已经捡回来,继续玩
Joe 玩第1次车子 carTime= 5
等五秒别人帮他捡车子
已经捡回来,继续玩
Joe 玩第2次车子 carTime= 7
等五秒别人帮他捡车子
Joe不等别人帮他捡车了,自己自觉去捡车子
Joe 玩第3次车子 carTime= 9
等五秒别人帮他捡车子
Joe不等别人帮他捡车了,自己自觉去捡车子
通过实验发现 System.out.println("...") 如果放在 sleep() 方法后面,那么只会在线程被唤醒或者自己睡醒后连同后面次数的行为一起打印执行。简单地说,sleep 后的语句是在线程唤醒后执行的。