栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

3 .Thread类API 3.1 创建线程对象相关

构造器:

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、线程加塞:join
void 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()
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/712775.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号