【Java 并发编程】【03】Thread类API

阅读: 评论:0

【Java 并发编程】【03】Thread类API

【Java 并发编程】【03】Thread类API

Thread类API

1 创建线程对象相关

构造器:

  • Thread():创建新的Thread对象
  • Thread(String threadname):创建线程并指定线程实例名
  • Thread(Runnable target):指定创建线程的目标对象,它实现了Runnable接口中的run方法
  • Thread(Runnable target, String name):创建新的Thread对象,并命名

2 线程体和启动线程

2.1 run()

public void run()

  • run()方法是继承自Runnable接口,无参无返回值,方法体就是线程体;
  • 如果直接调用thread对象的run()方法,则就是一个普通的对象方法,不会启动新的线程来执行;

2.2 start()

  • public void start():会启动一个新的线程;
  • 一个线程不能多次调用start(),否则报错

3 获取和设置线程信息

currentThread()

public static native Thread currentThread():这是一个静态方法,返回当前正在执行的线程对象

isAlive()

public final native boolean isAlive():测试线程是否处于活动状态。如果线程已经启动且尚未终止,则为活动状态。

getName()

public final String getName():getName()方法是Thread的实例方法,该方法返回当前线程对象的名字

setName(String name)

public final void setName(String name):设置该线程名称。除了主线程main之外,其他线程可以在创建时指定线程名称或通过setName(String name)方法设置线程名称,否则依次为Thread-0,Thread-1…等。

getPriority()

public final int getPriority() :返回线程优先级

setPriority(int newPriority)

public final void setPriority(int newPriority) :改变线程的优先级

  • 每个线程都有一定的优先级,优先级高的线程被CPU调度的概率增高。因此优先级不能够解决线程调度的先后顺序,只能解决概率。
  • 每个线程默认的优先级都与创建它的父线程具有相同的优先级。
  • 参数范围在[1,10]之间。
    Thread类中维护了三个优先级常量,通常推荐设置Thread类的三个优先级常量:
    MAX_PRIORITY (10):最高优先级
    MIN _PRIORITY (1):最低优先级
    NORM_PRIORITY (5):普通优先级,默认情况下main线程具有普通优先级。

4 控制线程

Thread类提供了一些方法,可以控制线程的执行。

1、线程睡眠:sleep

1.API 官方描述

/** Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers. The thread does not lose ownership of any monitors.
Params:
millis – the length of time to sleep in milliseconds
Throws:
IllegalArgumentException – if the value of millis is negative
InterruptedException – if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.
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);}
  • 根据系统计时器和调度器的精度和准确性,使当前执行的线程在指定的毫秒数内处于睡眠状态(暂时停止执行)。
  • 线程不会失去任何监视器的所有权。
  • 参数:
    毫秒-睡眠时间的长度,以毫秒为单位
  • 抛出:
    IllegalArgumentException -如果millis的值为负数
    InterruptedException—如果任何线程中断了当前线程; 当抛出此异常时,当前线程的中断状态将被清除。

2.细节补充

  • sleep是个静态方法,这意味着不是指定睡哪个线程,而是哪个线程中调用Thread.sleep()哪个进入睡眠状态
  • 让当前正在执行的线程暂停一段时间,会导致当前线程进入阻塞状态失去CPU但不失去锁资源

3.Thread.sleep()的等价方法

TimeUnit.SECONDS.sleep(1);//Thread.sleep(1000);

4.使用练习:实现倒计时
实现十秒倒计时

public class _01_Sleep {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic 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();}
}
  1. Sleep应用场景 - 减少对cpu的占用

2、线程让步:yield

public static native void yield();
  • yield()也是一个静态方法,哪个线程调用Thread.yield 哪个线程进入Runnable状态
  • 它可以让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程转入就绪状态
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、线程加塞:join

void join()   等待该线程终止。 
void join(long millis) :等待该线程终止的时间最长为 millis 毫秒。如果millis时间到,将不再等待。 
void join(long millis, int nanos) :等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。 
  • 是非静态方法,join()的意思是让线程对象加入进来,但是会阻塞当前线程;
  • 当在某个线程的线程体中调用了另一个线程的join()方法,当前线程将被阻塞,直到join进来的线程执行完它才能继续。
  • 如果 millis < 线程执行结束的时长,会提前结束线程;> 按照线程执行结束的时长来

示例代码:

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 = ().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

join 应用

4 、线程中断:interrupt

.html

(1)每个线程都一个状态位用于标识当前线程对象是否是中断状态。
(2)

public boolean isInterrupted()
public void interrupt()
public static boolean interrupted() 

(3)isInterrupted()

  • 是一个实例方法
  • 主要用于判断当前线程对象的中断标志位是否被标记了,如果被标记了则返回true表示当前已经被中断,否则返回false。
  • 它的实现源码:
public boolean isInterrupted() {return isInterrupted(false);
}private native boolean isInterrupted(boolean ClearInterrupted);

底层调用的本地方法isInterrupted,传入一个boolean类型的参数,用于指定调用该方法之后是否需要清除该线程对象的中断标识位。从这里我们也可以看出来,调用isInterrupted并不会清除线程对象的中断标识位。

案例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 = stTime = restTime;}@Overridepublic 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.Time()&Time()?"兔子赢":"乌龟赢");}
}

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 = stTime = restTime;}@Overridepublic 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.Time()&Time()?"兔子赢":"乌龟赢");}else if(rabbit.isEnded()){System.out.println("兔子赢");}else if(turtoise.isEnded()){System.out.println("乌龟赢");}}
}

本文发布于:2024-01-29 17:50:59,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170652186117217.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:Java   API   Thread
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23