构造器:
Thread():创建新的Thread对象Thread(String threadname):创建线程并指定线程实例名Thread(Runnable target):指定创建线程的目标对象,它实现了Runnable接口中的run方法Thread(Runnable target, String name):创建新的Thread对象,并命名
线程体和启动线程:
public void run():子类必须重写run()以编写线程体public void start():启动线程 3.2 获取和设置线程信息
1.public static native Thread currentThread():这是一个静态方法,总是返回当前正在执行的线程对象
2.public final native boolean isAlive():测试线程是否处于活动状态。如果线程已经启动且尚未终止,则为活动状态。
3.public final String getName():getName()方法是Thread的实例方法,该方法返回当前线程对象的名字
4.public final void setName(String name):设置该线程名称。除了主线程main之外,其他线程可以在创建时指定线程名称或通过setName(String name)方法设置线程名称,否则依次为Thread-0,Thread-1…等。
5.public final int getPriority() :返回线程优先值
6.public final void setPriority(int newPriority) :改变线程的优先级
每个线程都有一定的优先级,优先级高的线程被CPU调度的概率增高。因此优先级不能够解决线程调度的先后顺序,只能解决频率。每个线程默认的优先级都与创建它的父线程具有相同的优先级。参数范围在[1,10]之间。
Thread类中维护了三个优先级常量,通常推荐设置Thread类的三个优先级常量:
MAX_PRIORITY (10):最高优先级
MIN _PRIORITY (1):最低优先级
NORM_PRIORITY (5):普通优先级,默认情况下main线程具有普通优先级。
3.3 控制线程
Thread类提供了一些方法,可以控制线程的执行。
1、线程睡眠:sleep//在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
public static native void sleep(long millis) throws InterruptedException;
//在指定的毫秒加纳秒内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
public static void sleep(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
sleep(millis);
}
1.是个静态方法,这意味着不是睡指定的线程,而是哪个线程中调用 睡哪个
2.让当前正在执行的线程暂停一段时间,会导致当前线程进入阻塞状态。 失去CPU但不失去锁资源
使用练习:实现倒计时
实现十秒倒计时
public class _01_Sleep {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("倒计时预备:");
for (int i = 10; i > 0 ; i--) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("新年快乐!");
}
}, "倒计时").start();
}
}
2、线程让步:yield
public static native void yield();
yield()也是一个静态方法,它可以让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程转入就绪状态。
yield只是让当前线程暂停一下,让系统的线程调度器重新调度一次,希望优先级与当前线程相同或更高的其他线程能够获得执行机会,但是这个不能保证,完全有可能的情况是,当某个线程调用了yield方法暂停之后,线程调度器又将其调度出来重新执行。
public class _02_yield {
public static void main(String[] args) {
MyYieldThread m1 = new MyYieldThread("低");
m1.setPriority(Thread.MIN_PRIORITY);
MyYieldThread m2 = new MyYieldThread("高");
m2.setPriority(Thread.MAX_PRIORITY);
m1.start();
m2.start();
}
}
class MyYieldThread extends Thread {
public MyYieldThread(String name) {
super(name);
}
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println(getName() + ":" + i);
Thread.yield();
}
}
}
高:1
高:2
高:3
高:4
高:5
高:6
高:7
高:8
高:9
高:10
低:1
低:2
低:3
低:4
低:5
低:6
低:7
低:8
低:9
低:10
可以看出,即便线程让出cpu进入就绪态,但是下一次继续被cpu执行的概率还是挺大的
3、线程加塞:joinvoid join() 等待该线程终止。 void join(long millis) :等待该线程终止的时间最长为 millis 毫秒。如果millis时间到,将不再等待。 void join(long millis, int nanos) :等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
是非静态方法,join()的意思是让线程对象加入进来,但是会阻塞当前线程;
当在某个线程的线程体中调用了另一个线程的join()方法,当前线程将被阻塞,直到join进来的线程执行完它才能继续。
示例代码:
public class _03_join {
public static void main(String[] args) {
ChatThread t = new ChatThread();
t.start();
for (int i = 1; i < 10; i++) {
System.out.println("main:" + i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//当main打印到5之后,需要等join进来的线程停止后才会继续了。
if(i==5){
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class ChatThread extends Thread{
public void run(){
Scanner input = new Scanner(System.in);
while(true){
System.out.println("是否结束?(Y、N)");
char confirm = input.next().charAt(0);
if(confirm == 'Y' || confirm == 'y'){
break;
}
}
input.close();
}
}
main:1
main:2
main:3
是否结束?(Y、N)
main:4
main:5
N
是否结束?(Y、N)
N
是否结束?(Y、N)
N
是否结束?(Y、N)
Y
main:6
main:7
main:8
main:9
案例1
编写龟兔赛跑多线程程序,设赛跑长度为30米
兔子的速度是10米每秒,兔子每跑完10米休眠的时间10秒
乌龟的速度是1米每秒,乌龟每跑完10米的休眠时间是1秒
要求:要等兔子和乌龟的线程结束,主线程(裁判)才能公布最后的结果。
package com.atguigu.part02;
public class Racer extends Thread {
private String name;//运动员名字
private long runTime;//每米需要时间,单位毫秒
private long restTime;//每10米的休息时间,单位毫秒
private long distance;//全程距离,单位米
private long time;//跑完全程的总时间
public Racer(String name, long distance, long runTime, long restTime) {
super();
this.name = name;
this.distance = distance;
this.runTime = runTime;
this.restTime = restTime;
}
@Override
public void run() {
long sum = 0;
long start = System.currentTimeMillis();
while (sum < distance) {
System.out.println(name + "正在跑...");
try {
Thread.sleep(runTime);// 每米距离,该运动员需要的时间
} catch (InterruptedException e) {
return ;
}
sum++;
try {
if (sum % 10 == 0 && sum < distance) {
// 每10米休息一下
System.out.println(name+"已经跑了"+sum+"米正在休息....");
Thread.sleep(restTime);
}
} catch (InterruptedException e) {
return ;
}
}
long end = System.currentTimeMillis();
time = end - start;
System.out.println(name+"跑了"+sum+"米,已到达终点,共用时"+time/1000.0+"秒");
}
public long getTime() {
return time;
}
}
package com.atguigu.part02;
public class TestJoin2 {
public static void main(String[] args) {
Racer rabbit = new Racer("兔子", 30, 100, 10000);
Racer turtoise = new Racer("乌龟", 30, 1000, 1000);
rabbit.start();
turtoise.start();
try {
rabbit.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
turtoise.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
//因为要兔子和乌龟都跑完,才能公布结果
System.out.println("比赛结束");
System.out.println(rabbit.getTime()
4、守护线程
概念:有一种线程,它是在后台运行的,它的任务是为其他线程提供服务的,这种线程被称为“守护线程”。JVM的垃圾回收线程就是典型的守护线程。
特点:
守护线程有个特点,就是如果所有非守护线程都死亡,那么守护线程自动死亡。
使用:
(1)将线程设置为守护线程
调用setDaemon(true)方法可将指定线程设置为守护线程。必须在线程启动之前设置,否则会报IllegalThreadStateException异常。
(2)判断是否是守护线程
调用isDaemon()可以判断线程是否是守护线程。
package com.atguigu.part02;
public class TestDaemon {
public static void main(String[] args) {
MyDaemon m = new MyDaemon();
m.setDaemon(true);
m.start();
for (int i = 0; i < 20; i++) {
System.out.println("main:" + i);
}
}
}
class MyDaemon extends Thread{
public void run(){
while(true){
System.out.println("MyDaemon");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
执行效果就是等main线程执行完,才会执行守护线程;
5、使用标识来停止线程
我们知道线程体执行完,或遇到未捕获的异常自然会停止,但是有时我们希望由另一个线程检测到某个情况时,停止一个线程,该怎么做呢?
Thread类提供了stop()来停止一个线程,但是该方法具有固有的不安全性,已经标记为@Deprecated不建议再使用,那么我们就需要通过其他方式来停止线程了,其中一种方式是使用标识。
案例:编写龟兔赛跑多线程程序,设赛跑长度为30米
兔子的速度是10米每秒,兔子每跑完10米休眠的时间10秒
乌龟的速度是1米每秒,乌龟每跑完10米的休眠时间是1秒
要求:只要兔子和乌龟中有人到达终点,就宣布比赛结束,没到达终点的也停下来。
package com.atguigu.part02;
public class Player extends Thread{
private String name;//运动员名字
private long runTime;//每米需要时间,单位毫秒
private long restTime;//每10米的休息时间,单位毫秒
private long distance;//全程距离,单位米
private long time;//跑完全程的总时间
private boolean flag = true; //true 表示继续跑 false表示结束线程
private volatile boolean ended = false;//用于标记是否到达终点
public Player(String name, long distance, long runTime, long restTime) {
super();
this.name = name;
this.distance = distance;
this.runTime = runTime;
this.restTime = restTime;
}
@Override
public void run() {
long sum = 0;
long start = System.currentTimeMillis();
while (sum < distance && flag) {
System.out.println(name + "正在跑...");
try {
Thread.sleep(runTime);// 每米距离,该运动员需要的时间
} catch (InterruptedException e) {
return ;
}
sum++;
try {
if (sum % 10 == 0 && sum < distance && flag) {
// 每10米休息一下
System.out.println(name+"已经跑了"+sum+"米正在休息....");
Thread.sleep(restTime);
}
} catch (InterruptedException e) {
return ;
}
}
long end = System.currentTimeMillis();
time = end - start;
ended = sum == distance ? true : false;
System.out.println(name+"跑了"+sum+"米,共用时"+time/1000.0+"秒");
}
public long getTime() {
return time;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public boolean isEnded() {
return ended;
}
}
package com.atguigu.part02;
public class TestStop {
public static void main(String[] args) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
Player rabbit = new Player("兔子", 30, 100, 10000);
Player turtoise = new Player("乌龟", 30, 1000, 1000);
rabbit.start();
turtoise.start();
while(true){
if(rabbit.isEnded() || turtoise.isEnded()){
rabbit.setFlag(false);
turtoise.setFlag(false);
//只要又人跑完,就结束比赛,并公布结果
break;
}
}
System.out.println("比赛结束");
if(rabbit.isEnded() && turtoise.isEnded()){
System.out.println(rabbit.getTime() 


