二:线程常用操作方法
多线程的主要操作方法都在Thread类中定义,即分析理解Thread类中所定义的方法及使用。
1、线程的命名和取得
未命名状态下的线程运行是无序和不可确定的,当要抽取其中某个特定的线程时,此时就必须用到线程的命名方法。即,给一个目标线程取个名字,通过该名字可以在众多线程里找到目标线程。
线程的命名和取得名字的方法:
构造方法设置名字 | public Thread(Runnable target,String name) |
setName设置名字 | public final String getName() |
getName获取名字 | public final void setName(String name) |
若要获取给线程取得名字,应该使用currentThread()获取当前线程。
获得当前线程的方法 | public static Thread currentThread() |
通过范例观察
代码 | 结果 |
package cn.demos; class MyThread implements Runnable { @Override public class Demo1 { MyThread mt = new MyThread(); | 当前线程:线程A 当前线程:线程B 当前线程:Thread-0 |
从以上程序可以发现,当开发者为线程设置名字时,获取的是开发者设置的名字,而未设置名字的线程,系统会自动给每个线程设置一个不重复的名字。
2、线程休眠
希望目标线程能够暂缓执行,休眠方法如下:
方法 | |
休眠方法1 | public static void sleep(long millis) throws InterruptedException |
休眠方法2 | public static void sleep(long millis, int nanos) throws InterruptedException |
InterruptedException:表示中断异常
1)范例:观察休眠处理
代码 | 结果 |
package cn.demos; public class Demo1 { new Thread(() -> { | 线程对象、x= 0 线程对象、x= 1 线程对象、x= 2 线程对象、x= 3 线程对象、x= 4 线程对象、x= 5 线程对象、x= 6 线程对象、x= 7 线程对象、x= 8 线程对象、x= 9 |
在程序执行过程中,可以明显看到每个线程的运行速度降低,所以休眠的主要特点是可以自动实现线程的唤醒,以继续进行后续处理。
注意:当有多个线程对象时,线程的休眠也具有先后顺序
2)范例:产生多个线程对象进行休眠处理
代码 | 结果 | |
第一种方式 | package cn.demos; public class Demo1 { for (int num = 0; num < 5; num++) { new Thread(() -> { for (int x = 0; x < 10; x++) { | 线程对象=====0、x= 0 线程对象=====4、x= 0 线程对象=====1、x= 0 线程对象=====3、x= 0 线程对象=====2、x= 0 线程对象=====2、x= 1 线程对象=====1、x= 1 线程对象=====0、x= 1 线程对象=====4、x= 1 线程对象=====3、x= 1 线程对象=====4、x= 2 线程对象=====0、x= 2 线程对象=====2、x= 2 线程对象=====1、x= 2 线程对象=====3、x= 2 线程对象=====4、x= 3 线程对象=====1、x= 3 线程对象=====2、x= 3 线程对象=====0、x= 3 线程对象=====3、x= 3 线程对象=====0、x= 4 线程对象=====2、x= 4 线程对象=====1、x= 4 线程对象=====4、x= 4 线程对象=====3、x= 4 线程对象=====4、x= 5 线程对象=====2、x= 5 线程对象=====0、x= 5 线程对象=====1、x= 5 线程对象=====3、x= 5 线程对象=====4、x= 6 线程对象=====2、x= 6 线程对象=====1、x= 6 线程对象=====0、x= 6 线程对象=====3、x= 6 线程对象=====0、x= 7 线程对象=====4、x= 7 线程对象=====1、x= 7 线程对象=====2、x= 7 线程对象=====3、x= 7 线程对象=====1、x= 8 线程对象=====2、x= 8 线程对象=====0、x= 8 线程对象=====4、x= 8 线程对象=====3、x= 8 线程对象=====1、x= 9 线程对象=====2、x= 9 线程对象=====0、x= 9 线程对象=====4、x= 9 线程对象=====3、x= 9 |
第二种方式 | package cn.demos; public class Demo1 { Runnable run =() -> { |
观察程序运行得出,发现有几个对象就有几个线程是一起进行休眠,而后一起进了自动唤醒,而其实是有差别,只是细微的时间差,每个对象还是分先后进行。
3、线程中断
在线程休眠中发现一个“InterruptedException”中断异常,就可以得知线程的休眠是可以被打断的,而这种打断是被其他线程完成的。
中断执行方法:
方法 | |
判断线程是否被中断 | public boolean isInterrupted() |
中断线程执行 | public void interrupt() |
范例:观察线程的中断处理操作
代码 | 结果 |
package cn.demos; public class Demo1 { Thread thread = new Thread(() -> { | 三天不睡觉的我需要睡觉补充精力 在睡觉的人旁边跳广场舞 睡觉被打扰,强行起床 |
结论:所有在执行的线程都是可以被中断的,而中断线程,都必须进行异常处理
4、线程强制运行
当满足于某些条件之后,某一个线程对象可以一直独占资源,一直到该线程的程序结束。
1)范例:观察正常线程
代码 | 结果 |
package cn.demos; public class Demo1 { Thread thread = new Thread(() -> { for (int y = 0; y < 10; y++) { | main的线程、y=19 main的线程、y=20 main的线程、y=21 main的线程、y=22 main的线程、y=23 main的线程、y=24 main的线程、y=25 main的线程、y=26 正常的线程执行、x=2 main的线程、y=27 正常的线程执行、x=3 main的线程、y=28 正常的线程执行、x=4 main的线程、y=29 正常的线程执行、x=5 main的线程、y=30 正常的线程执行、x=6 正常的线程执行、x=7 正常的线程执行、x=8 正常的线程执行、x=9 |
从以上程序可以看出,两个线程会交替进行,互相抢占资源,直到执行完毕。若此时希望main线程独自占用资源,等main执行完毕后才执行正常的,此时可以使用以下方法进行强制执行:
强制执行 | public final void join() throws InterruptedException |
2)范例:观察强制执行
代码 | 结果 |
package cn.demos; public class Demo1 { // 获得主线程 thread.start(); for (int y = 0; y < 100; y++) { System.out.println("main的线程、y=" + y); } | main的线程、y=0 正常的线程执行、x=0 main的线程、y=1 main的线程、y=2 main的线程、y=3 main的线程、y=4 main的线程、y=5 main的线程、y=6 main的线程、y=7 main的线程、y=8 main的线程、y=9 正常的线程执行、x=1 正常的线程执行、x=2 main的线程、y=10 main的线程、y=11 main的线程、y=12 main的线程、y=13 main的线程、y=14 main的线程、y=15 main的线程、y=16 main的线程、y=17 main的线程、y=18 main的线程、y=19 main的线程、y=20 main的线程、y=21 main的线程、y=22 main的线程、y=23 main的线程、y=24 main的线程、y=25 main的线程、y=26 main的线程、y=27 main的线程、y=28 main的线程、y=29 main的线程、y=30 |
注意:在线程强制执行的时候,一定要获取强制执行线程对象之后才可以执行join()方法。
5、线程礼让
线程的礼让指的是将资源先让出去,让别的线程先使用资源。
线程礼让方法:
线程礼让yield | public static void yield() |
范例:线程的礼让操作
代码 | 结果 |
package cn.demos; public class Demo1 { Thread thread = new Thread(() -> { thread.start(); for (int y = 0; y < 100; y++) { } | !!!!正常线程礼让执行!!! main的线程、y=0 正常的线程执行、x=0 正常的线程执行、x=1 main的线程、y=1 正常的线程执行、x=2 main的线程、y=2 !!!!正常线程礼让执行!!! 正常的线程执行、x=3 main的线程、y=3 正常的线程执行、x=4 main的线程、y=4 main的线程、y=5 正常的线程执行、x=5 !!!!正常线程礼让执行!!! 正常的线程执行、x=6 main的线程、y=6 main的线程、y=7 正常的线程执行、x=7 正常的线程执行、x=8 main的线程、y=8 !!!!正常线程礼让执行!!! main的线程、y=9 正常的线程执行、x=9 正常的线程执行、x=10 main的线程、y=10 正常的线程执行、x=11 !!!!正常线程礼让执行!!! main的线程、y=11 |
注意:每一次调用yield()方法都只会礼让一次当前的资源。
6、线程优先级
从理论上来讲,线程的优先级越高越有可能先执行(即越有可能先抢占到资源)。
优先级操作方法:
方法 | |
设置优先级 | public final void setPriority(int newPriority) |
获取优先级 | public final int getPriority() |
从上面的方法定义中可以得出,优先级定义时都是通过int型数字来完成。
Thread类中定义优先级的常量:
名称 | 描述 | 定义 | 对应的值 |
MIN_PRIORITY | 最低优先级 | public static final int MIN_PRIORITY | 1 |
NORM_PRIORITY | 中等优先级 | public static final int NORM_PRIORITY | 5 |
MAX_PRIORITY | 最高优先级 | public static final int MAX_PRIORITY | 10 |
1)范例:观察优先级
代码 | 结果 |
package cn.demos; public class Demo1 { Runnable run = () -> { | 线程对象C执行, 线程对象B执行, 线程对象A执行, 线程对象A执行, 线程对象C执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, 线程对象B执行, 线程对象A执行, 线程对象C执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, 线程对象B执行, 线程对象A执行, 线程对象C执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, |
注意:优先级并不是绝对的!!!
2)主线程优先级
代码 | 结果 |
package cn.demos; public class Demo1 { | 5 |
由以上程序可以得出,主线程的优先级属于中等优先级,而默认的线程优先级也是中等优先级。
二:线程常用操作方法
多线程的主要操作方法都在Thread类中定义,即分析理解Thread类中所定义的方法及使用。
1、线程的命名和取得
未命名状态下的线程运行是无序和不可确定的,当要抽取其中某个特定的线程时,此时就必须用到线程的命名方法。即,给一个目标线程取个名字,通过该名字可以在众多线程里找到目标线程。
线程的命名和取得名字的方法:
构造方法设置名字 | public Thread(Runnable target,String name) |
setName设置名字 | public final String getName() |
getName获取名字 | public final void setName(String name) |
若要获取给线程取得名字,应该使用currentThread()获取当前线程。
获得当前线程的方法 | public static Thread currentThread() |
通过范例观察
代码 | 结果 |
package cn.demos; class MyThread implements Runnable { @Override public class Demo1 { MyThread mt = new MyThread(); | 当前线程:线程A 当前线程:线程B 当前线程:Thread-0 |
从以上程序可以发现,当开发者为线程设置名字时,获取的是开发者设置的名字,而未设置名字的线程,系统会自动给每个线程设置一个不重复的名字。
2、线程休眠
希望目标线程能够暂缓执行,休眠方法如下:
方法 | |
休眠方法1 | public static void sleep(long millis) throws InterruptedException |
休眠方法2 | public static void sleep(long millis, int nanos) throws InterruptedException |
InterruptedException:表示中断异常
1)范例:观察休眠处理
代码 | 结果 |
package cn.demos; public class Demo1 { new Thread(() -> { | 线程对象、x= 0 线程对象、x= 1 线程对象、x= 2 线程对象、x= 3 线程对象、x= 4 线程对象、x= 5 线程对象、x= 6 线程对象、x= 7 线程对象、x= 8 线程对象、x= 9 |
在程序执行过程中,可以明显看到每个线程的运行速度降低,所以休眠的主要特点是可以自动实现线程的唤醒,以继续进行后续处理。
注意:当有多个线程对象时,线程的休眠也具有先后顺序
2)范例:产生多个线程对象进行休眠处理
代码 | 结果 | |
第一种方式 | package cn.demos; public class Demo1 { for (int num = 0; num < 5; num++) { new Thread(() -> { for (int x = 0; x < 10; x++) { | 线程对象=====0、x= 0 线程对象=====4、x= 0 线程对象=====1、x= 0 线程对象=====3、x= 0 线程对象=====2、x= 0 线程对象=====2、x= 1 线程对象=====1、x= 1 线程对象=====0、x= 1 线程对象=====4、x= 1 线程对象=====3、x= 1 线程对象=====4、x= 2 线程对象=====0、x= 2 线程对象=====2、x= 2 线程对象=====1、x= 2 线程对象=====3、x= 2 线程对象=====4、x= 3 线程对象=====1、x= 3 线程对象=====2、x= 3 线程对象=====0、x= 3 线程对象=====3、x= 3 线程对象=====0、x= 4 线程对象=====2、x= 4 线程对象=====1、x= 4 线程对象=====4、x= 4 线程对象=====3、x= 4 线程对象=====4、x= 5 线程对象=====2、x= 5 线程对象=====0、x= 5 线程对象=====1、x= 5 线程对象=====3、x= 5 线程对象=====4、x= 6 线程对象=====2、x= 6 线程对象=====1、x= 6 线程对象=====0、x= 6 线程对象=====3、x= 6 线程对象=====0、x= 7 线程对象=====4、x= 7 线程对象=====1、x= 7 线程对象=====2、x= 7 线程对象=====3、x= 7 线程对象=====1、x= 8 线程对象=====2、x= 8 线程对象=====0、x= 8 线程对象=====4、x= 8 线程对象=====3、x= 8 线程对象=====1、x= 9 线程对象=====2、x= 9 线程对象=====0、x= 9 线程对象=====4、x= 9 线程对象=====3、x= 9 |
第二种方式 | package cn.demos; public class Demo1 { Runnable run =() -> { |
观察程序运行得出,发现有几个对象就有几个线程是一起进行休眠,而后一起进了自动唤醒,而其实是有差别,只是细微的时间差,每个对象还是分先后进行。
3、线程中断
在线程休眠中发现一个“InterruptedException”中断异常,就可以得知线程的休眠是可以被打断的,而这种打断是被其他线程完成的。
中断执行方法:
方法 | |
判断线程是否被中断 | public boolean isInterrupted() |
中断线程执行 | public void interrupt() |
范例:观察线程的中断处理操作
代码 | 结果 |
package cn.demos; public class Demo1 { Thread thread = new Thread(() -> { | 三天不睡觉的我需要睡觉补充精力 在睡觉的人旁边跳广场舞 睡觉被打扰,强行起床 |
结论:所有在执行的线程都是可以被中断的,而中断线程,都必须进行异常处理
4、线程强制运行
当满足于某些条件之后,某一个线程对象可以一直独占资源,一直到该线程的程序结束。
1)范例:观察正常线程
代码 | 结果 |
package cn.demos; public class Demo1 { Thread thread = new Thread(() -> { for (int y = 0; y < 10; y++) { | main的线程、y=19 main的线程、y=20 main的线程、y=21 main的线程、y=22 main的线程、y=23 main的线程、y=24 main的线程、y=25 main的线程、y=26 正常的线程执行、x=2 main的线程、y=27 正常的线程执行、x=3 main的线程、y=28 正常的线程执行、x=4 main的线程、y=29 正常的线程执行、x=5 main的线程、y=30 正常的线程执行、x=6 正常的线程执行、x=7 正常的线程执行、x=8 正常的线程执行、x=9 |
从以上程序可以看出,两个线程会交替进行,互相抢占资源,直到执行完毕。若此时希望main线程独自占用资源,等main执行完毕后才执行正常的,此时可以使用以下方法进行强制执行:
强制执行 | public final void join() throws InterruptedException |
2)范例:观察强制执行
代码 | 结果 |
package cn.demos; public class Demo1 { // 获得主线程 thread.start(); for (int y = 0; y < 100; y++) { System.out.println("main的线程、y=" + y); } | main的线程、y=0 正常的线程执行、x=0 main的线程、y=1 main的线程、y=2 main的线程、y=3 main的线程、y=4 main的线程、y=5 main的线程、y=6 main的线程、y=7 main的线程、y=8 main的线程、y=9 正常的线程执行、x=1 正常的线程执行、x=2 main的线程、y=10 main的线程、y=11 main的线程、y=12 main的线程、y=13 main的线程、y=14 main的线程、y=15 main的线程、y=16 main的线程、y=17 main的线程、y=18 main的线程、y=19 main的线程、y=20 main的线程、y=21 main的线程、y=22 main的线程、y=23 main的线程、y=24 main的线程、y=25 main的线程、y=26 main的线程、y=27 main的线程、y=28 main的线程、y=29 main的线程、y=30 |
注意:在线程强制执行的时候,一定要获取强制执行线程对象之后才可以执行join()方法。
5、线程礼让
线程的礼让指的是将资源先让出去,让别的线程先使用资源。
线程礼让方法:
线程礼让yield | public static void yield() |
范例:线程的礼让操作
代码 | 结果 |
package cn.demos; public class Demo1 { Thread thread = new Thread(() -> { thread.start(); for (int y = 0; y < 100; y++) { } | !!!!正常线程礼让执行!!! main的线程、y=0 正常的线程执行、x=0 正常的线程执行、x=1 main的线程、y=1 正常的线程执行、x=2 main的线程、y=2 !!!!正常线程礼让执行!!! 正常的线程执行、x=3 main的线程、y=3 正常的线程执行、x=4 main的线程、y=4 main的线程、y=5 正常的线程执行、x=5 !!!!正常线程礼让执行!!! 正常的线程执行、x=6 main的线程、y=6 main的线程、y=7 正常的线程执行、x=7 正常的线程执行、x=8 main的线程、y=8 !!!!正常线程礼让执行!!! main的线程、y=9 正常的线程执行、x=9 正常的线程执行、x=10 main的线程、y=10 正常的线程执行、x=11 !!!!正常线程礼让执行!!! main的线程、y=11 |
注意:每一次调用yield()方法都只会礼让一次当前的资源。
6、线程优先级
从理论上来讲,线程的优先级越高越有可能先执行(即越有可能先抢占到资源)。
优先级操作方法:
方法 | |
设置优先级 | public final void setPriority(int newPriority) |
获取优先级 | public final int getPriority() |
从上面的方法定义中可以得出,优先级定义时都是通过int型数字来完成。
Thread类中定义优先级的常量:
名称 | 描述 | 定义 | 对应的值 |
MIN_PRIORITY | 最低优先级 | public static final int MIN_PRIORITY | 1 |
NORM_PRIORITY | 中等优先级 | public static final int NORM_PRIORITY | 5 |
MAX_PRIORITY | 最高优先级 | public static final int MAX_PRIORITY | 10 |
1)范例:观察优先级
代码 | 结果 |
package cn.demos; public class Demo1 { Runnable run = () -> { | 线程对象C执行, 线程对象B执行, 线程对象A执行, 线程对象A执行, 线程对象C执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, 线程对象B执行, 线程对象A执行, 线程对象C执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, 线程对象B执行, 线程对象A执行, 线程对象C执行, 线程对象B执行, 线程对象C执行, 线程对象A执行, |
注意:优先级并不是绝对的!!!
2)主线程优先级
代码 | 结果 |
package cn.demos; public class Demo1 { | 5 |
由以上程序可以得出,主线程的优先级属于中等优先级,而默认的线程优先级也是中等优先级。