本章目标
了解设置和取得线程名称
了解线程的强制运行
了解线程的休眠
了解线程的礼让
了解线程的中断操作
线程操作的主要方法
取得和设置线程名称
在Thread类中,可以通过getName()方法取得线程的名称,通过setName()方法设置线程的名称。
线程的名称一般在启动线程前设置,但也允许为已经运行的线程设置名称。允许两个Thread对象有相同的名字,但为了清晰,应该尽量避免这种情况的发生。
另外,如果程序并没有为线程指定名称,则系统会自动的为线程分配一个名称。
设置和取得线程的名字
class MyThread implements Runnable{//实现 Runnable 接口
public void run(){//覆写接口中的 run()
for(int i=0; i<3; i++){//循环输出 3 次
//取得当前线程的名称
System.out.println(Thread.currentThread().getName()+"运行,i = "+i);
}
}
}
public class ThreadNameDemo {
public static void main(String[] args) {
MyThread my =new MyThread();//定义 Runnable 子类对象
new Thread(my).start();//系统自动设置线程名称
new Thread(my,"线程-A").start();//手工设置线程名称
new Thread(my,"线程-B").start();//手工设置线程名称
new Thread(my).start();//系统自动设置线程名称
new Thread(my).start();//系统自动设置线程名称
}
/* 结果:
* Thread-0运行,i = 0
* 线程-A运行,i = 0
* 线程-A运行,i = 1
* 线程-A运行,i = 2
* 线程-B运行,i = 0
* Thread-0运行,i = 1
* 线程-B运行,i = 1
* Thread-2运行,i = 0
* Thread-1运行,i = 0
* Thread-2运行,i = 1
* 线程-B运行,i = 2
* Thread-0运行,i = 2
* Thread-2运行,i = 2
* Thread-1运行,i = 1
* Thread-1运行,i = 2
* */
}
程序说明
从运行结果中发现没有设置线程名称的其余三个线程对象的名字都是很有规律的:Thread-0、Thread-1、Thread-2,从之前讲解的static关键字可以知道,在Thread类中必然存在一个static类型的属性,用于为线程自动命名。
观察程序的输出
class MyThread implements Runnable{//实现 Runnable 接口
public void run(){//覆写接口中的 run()
for(int i=0; i<3; i++){//循环输出 3 次
//取得当前线程的名称
System.out.println(Thread.currentThread().getName()+"运行,i = "+i);
}
}
}
public class CurrentThreadDemo {
public static void main(String[] args) {
MyThread my =new MyThread();//定义 Runnable 子类对象
new Thread(my,"线程").start();//启动线程
my.run();//直接调用 run 方法
}
/* 结果:
* main运行,i = 0
* 线程运行,i = 0
* main运行,i = 1
* 线程运行,i = 1
* main运行,i = 2
* 线程运行,i = 2
* */
}
判断线程是否启动
通过Thread类之中的start()方法通知CPU这个线程已经准备好启动,之后就等待分配CPU资源,运行此线程了。那么如何判断一个线程是否已经启动了呢?在Java中可以使用isAlive()方法来测试线程是否已经启动而且仍然在启动。
判断线程是否启动
class MyThread implements Runnable{//实现 Runnable 接口
public void run(){//覆写 run() 方法
for(int i=0; i<3; i++){//循环输出 3 次
//取得当前线程的名称
System.out.println(Thread.currentThread().getName()+"运行 --> "+i);
}
}
}
public class ThreadAliveDemo {
public static void main(String[] args) {
MyThread mt =new MyThread();//实例化对象
Thread t = new Thread(mt,"线程");//实例化 Thread 对象
System.out.println("线程开始执行之前 --> "+t.isAlive());//判断是否启动
t.start();//启动线程
System.out.println("线程开始执行之后 --> "+t.isAlive());//判断是否启动
for(int i=0; i<3; i++){//循环输出 3 次
System.out.println("main 运行 -->"+i);//输出
}
System.out.println("代码执行之后 --> "+t.isAlive());//后面的输出结果不确定
}
/* 结果:
* 线程开始执行之前 --> false
* 线程开始执行之后 --> true
* main 运行 -->0
* main 运行 -->1
* main 运行 -->2
* 代码执行之后 --> true
* 线程运行 --> 0
* 线程运行 --> 1
* 线程运行 --> 2
* */
}
线程的强制运行
在线程操作中,可以使用join()方法让一个线程强制运行,线程强制运行期间,其他线程无法运行,必须等待此线程完成之后才可以继续执行。
线程的强制运行
class MyThread implements Runnable{//实现 Runnable 接口
public void run(){//覆写 run() 方法
for(int i=0; i<50; i++){//循环输出 50 次
//输出线程的名称
System.out.println(Thread.currentThread().getName()+"运行 --> "+i);
}
}
}
public class ThreadJoinDemo {
public static void main(String[] args) {
MyThread mt =new MyThread();//实例化对象
Thread t = new Thread(mt,"线程");//实例化 Thread 对象
t.start();//启动线程
for(int i = 0; i<50; i++){//循环 50 次
if(i>10){//判断变量内容
try{
t.join();//线程 t 进行强制运行
}catch(Exception e){}//需要进行异常处理
}
System.out.println("Main 线程运行 --> "+i);
}
}
/* 结果:
* Main 线程运行 --> 0
* Main 线程运行 --> 1
* Main 线程运行 --> 2
* Main 线程运行 --> 3
* Main 线程运行 --> 4
* Main 线程运行 --> 5
* Main 线程运行 --> 6
* Main 线程运行 --> 7
* Main 线程运行 --> 8
* Main 线程运行 --> 9
* Main 线程运行 --> 10
* 线程运行 --> 0
* 线程运行 --> 1
* 线程运行 --> 2
* 线程运行 --> 3
* 线程运行 --> 4
* 线程运行 --> 5
* 线程运行 --> 6
* 线程运行 --> 7
* 线程运行 --> 8
* 线程运行 --> 9
* 线程运行 --> 10
* 线程运行 --> 11
* 线程运行 --> 12
* 线程运行 --> 13
* 线程运行 --> 14
* 线程运行 --> 15
* 线程运行 --> 16
* 线程运行 --> 17
* 线程运行 --> 18
* 线程运行 --> 19
* 线程运行 --> 20
* 线程运行 --> 21
* 线程运行 --> 22
* 线程运行 --> 23
* 线程运行 --> 24
* 线程运行 --> 25
* 线程运行 --> 26
* 线程运行 --> 27
* 线程运行 --> 28
* 线程运行 --> 29
* 线程运行 --> 30
* 线程运行 --> 31
* 线程运行 --> 32
* 线程运行 --> 33
* 线程运行 --> 34
* 线程运行 --> 35
* 线程运行 --> 36
* 线程运行 --> 37
* 线程运行 --> 38
* 线程运行 --> 39
* 线程运行 --> 40
* 线程运行 --> 41
* 线程运行 --> 42
* 线程运行 --> 43
* 线程运行 --> 44
* 线程运行 --> 45
* 线程运行 --> 46
* 线程运行 --> 47
* 线程运行 --> 48
* 线程运行 --> 49
* Main 线程运行 --> 11
* Main 线程运行 --> 12
* Main 线程运行 --> 13
* Main 线程运行 --> 14
* Main 线程运行 --> 15
* Main 线程运行 --> 16
* Main 线程运行 --> 17
* Main 线程运行 --> 18
* Main 线程运行 --> 19
* Main 线程运行 --> 20
* Main 线程运行 --> 21
* Main 线程运行 --> 22
* Main 线程运行 --> 23
* Main 线程运行 --> 24
* Main 线程运行 --> 25
* Main 线程运行 --> 26
* Main 线程运行 --> 27
* Main 线程运行 --> 28
* Main 线程运行 --> 29
* Main 线程运行 --> 30
* Main 线程运行 --> 31
* Main 线程运行 --> 32
* Main 线程运行 --> 33
* Main 线程运行 --> 34
* Main 线程运行 --> 35
* Main 线程运行 --> 36
* Main 线程运行 --> 37
* Main 线程运行 --> 38
* Main 线程运行 --> 39
* Main 线程运行 --> 40
* Main 线程运行 --> 41
* Main 线程运行 --> 42
* Main 线程运行 --> 43
* Main 线程运行 --> 44
* Main 线程运行 --> 45
* Main 线程运行 --> 46
* Main 线程运行 --> 47
* Main 线程运行 --> 48
* Main 线程运行 --> 49
* */
}
线程的休眠
在程序中允许一个线程进行暂时的休眠,直接使用Thread.sleep()方法即可。
线程的休眠
class MyThread implements Runnable{//实现 Runnable 接口
public void run(){//覆写接口中的 run()
for(int i=0; i<5; i++){//循环输出 5 次
try{
Thread.sleep(500);//线程休眠
}catch(Exception e){}//需要异常处理
//输出线程的名称
System.out.println(Thread.currentThread().getName()+"运行,i = "+i);
}
}
}
public class ThreadSleepDemo {
public static void main(String[] args) {
MyThread mt =new MyThread();//实例化对象
new Thread(mt,"线程").start();//启动线程
}
/* 结果:
* 线程运行,i = 0
* 线程运行,i = 1
* 线程运行,i = 2
* 线程运行,i = 3
* 线程运行,i = 4
* */
}
中断线程
当一个线程运行的时候,另外一个线程可以直接通过interrupt()方法,中断其运行状态。
线程的中断
class MyThread implements Runnable{//实现 Runnable 接口
public void run(){//覆写 run() 方法
System.out.println("1、进入 run() 方法");
try{
Thread.sleep(10000);//休眠 10s
System.out.println("2、已经完成休眠");
}catch(Exception e){
System.out.println("3、休眠被终止");
return;//让程序返回被调用处
}
System.out.println("4、run 方法正常结束");
}
}
public class ThreadInterruptDemo {
public static void main(String[] args) {
MyThread mt =new MyThread();//实例化子类对象
Thread t = new Thread(mt,"线程");//实例化线程对象
t.start();
try{
Thread.sleep(2000);//稍微停 2s 再继续中断
}catch(Exception e){
}
t.interrupt();//中断线程执行
}
/* 结果:
* 1、进入 run() 方法
* 3、休眠被终止
* */
}
后台线程
在Java程序中,只要前台有一个线程在运行,则整个java进程都不会消失,所以此时可以设置一个后台线程,这样即使Java进程结束了,此后台线程依然会继续执行。要想实现这样的操作,直接使用setDaemon()方法即可。
后台线程的设置
class MyThread implements Runnable{//实现 Runnable 接口
public void run(){//覆写 run() 方法
while(true){//无限制循环
//输出线程名称
System.out.println(Thread.currentThread().getName()+"在运行。");
}
}
}
public class ThreadDaemonDemo {
public static void main(String[] args) {
MyThread mt =new MyThread();//实例化子类对象
Thread t = new Thread(mt,"线程");//实例化 Thread 类对象
t.setDaemon(true);//此线程在后台运行
t.start();//启动线程
}
/* 结果:
* 线程在运行。
* 线程在运行。
* 线程在运行。
* 线程在运行。
* 线程在运行。
* 线程在运行。
* 线程在运行。
* 线程在运行。
* 线程在运行。
* 线程在运行。
* ……
* */
}
线程的优先级
在Java的线程操作中,所有的线程在运行前都会保持在就绪状态,那么此时,那个线程的优先级高,那个线程就有可能会先被执行。
线程优先级
在Java的线程中使用setPriority()方法可以设置一个线程的优先级,在Java的线程中一共有以下三种优先级
测试线程优先级
class MyThread implements Runnable{//实现 Runnable 接口
public void run(){//覆写 run() 方法
for(int i = 0; i<5; i++){//循环 5 次
try{
Thread.sleep(500);//线程休眠
}catch(Exception e){}//需要异常处理
//输出线程名称
System.out.println(Thread.currentThread().getName()+"运行,i = "+i);
}
}
}
public class ThreadPriorityDemo {
public static void main(String[] args) {
Thread t1 = new Thread(new MyThread(),"线程 A");//实例化线程对象
Thread t2 = new Thread(new MyThread(),"线程 B");//实例化线程对象
Thread t3 = new Thread(new MyThread(),"线程 C");//实例化线程对象
t1.setPriority(Thread.MIN_PRIORITY);//设置线程优先级为最低
t2.setPriority(Thread.MAX_PRIORITY);//设置线程优先级为最高
t3.setPriority(Thread.NORM_PRIORITY);//设置线程优先级为中等
t1.start();//启动线程
t2.start();//启动线程
t3.start();//启动线程
}
/* 结果:
* 线程 B运行,i = 0 —>第 2 个线程(t2)的优先级为:MAX_PRIORITY
* 线程 C运行,i = 0 —>第 2 个线程(t3)的优先级为:NORM_PRIORITY
* 线程 A运行,i = 0 —>第 2 个线程(t1)的优先级为:MIN_PRIORITY
* 线程 B运行,i = 1
* 线程 C运行,i = 1
* 线程 A运行,i = 1
* 线程 B运行,i = 2
* 线程 C运行,i = 2
* 线程 A运行,i = 2
* 线程 A运行,i = 3
* 线程 C运行,i = 3
* 线程 B运行,i = 3
* 线程 A运行,i = 4
* 线程 C运行,i = 4
* 线程 B运行,i = 4
* */
}
主方法的优先级是NORM_PRIORITY
public class MainPriorityDemo {
public static void main(String[] args) {
System.out.println("主方法的优先级:" +
Thread.currentThread().getPriority()); // 取得主方法的优先级
}
}
程序运行结果:
主方法的优先级:5
程序中取得线程优先级的结果是“5”,数字5对应的是“NORM_PRIORITY”这个优先级,所以主线程的优先级是中等级别。
线程的礼让
在线程操作中,也可以使用yield()方法将一个线程的操作暂时让给其他线程执行。
线程的礼让
class MyThread implements Runnable{//实现 Runnable 接口
public void run(){//覆写 run() 方法
for(int i = 0; i<5; i++){//不断输出
//输出线程名称
System.out.println(Thread.currentThread().getName()+"运行 --> "+i);
if(i==3){
System.out.print("线程礼让:");
//线程礼让
Thread.currentThread().yield();
}
}
}
}
public class ThreadYieldDemo {
public static void main(String[] args) {
MyThread my =new MyThread();//实例化 MyThread 对象
Thread t1 = new Thread(my,"线程 A");//定义线程对象
Thread t2 = new Thread(my,"线程 A");//定义线程对象
t1.start();//启动多线程
t2.start();//启动多线程
}
/* 结果:
* 线程 A运行 --> 0
* 线程 A运行 --> 0
* 线程 A运行 --> 1
* 线程 A运行 --> 1
* 线程 A运行 --> 2
* 线程 A运行 --> 3
* 线程礼让:线程 A运行 --> 2
* 线程 A运行 --> 4
* 线程 A运行 --> 3
* 线程礼让:线程 A运行 --> 4
* */
}