二:线程常用操作方法

    科技2025-04-07  17

              多线程的主要操作方法都在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 void run() {         // 若要获取给线程取得名字,应该使用currentThread()获取当前线程。         System.out.println("当前线程:" + Thread.currentThread().getName());     } }

    public class Demo1 {     public static void main(String[] args) throws Exception {

            MyThread mt = new MyThread();         new Thread(mt, "线程A").start();         // 设置线程名字         new Thread(mt).start();         new Thread(mt, "线程B").start();     } }  

    当前线程:线程A 当前线程:线程B 当前线程:Thread-0

              从以上程序可以发现,当开发者为线程设置名字时,获取的是开发者设置的名字,而未设置名字的线程,系统会自动给每个线程设置一个不重复的名字。

     

    2、线程休眠

              希望目标线程能够暂缓执行,休眠方法如下:

     方法休眠方法1public static void sleep​(long millis)  throws InterruptedException休眠方法2public static void sleep​(long millis, int nanos) throws InterruptedException

              InterruptedException:表示中断异常

              1)范例:观察休眠处理

    代码结果

    package cn.demos;

    public class Demo1 {     public static void main(String[] args) throws Exception {

            new Thread(() -> {             for (int x = 0; x < 10; x++) {                 System.out.println(Thread.currentThread().getName() + "、x= " + x);                 try {                     // 暂缓执行                     Thread.sleep(100);                 } catch (Exception e) {                     // TODO Auto-generated catch block                     e.printStackTrace();                 }             }         }, "线程对象").start();     } }  

    线程对象、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 {     public static void main(String[] args) throws Exception {

            for (int num = 0; num < 5; num++) {

                new Thread(() -> {

                    for (int x = 0; x < 10; x++) {                     System.out.println(Thread.currentThread().getName() + "、x= " + x);                     try {                         // 暂缓执行                         Thread.sleep(100);                     } catch (Exception e) {                         // TODO Auto-generated catch block                         e.printStackTrace();                     }                 }             }, "线程对象=====" + num).start();         }     } }  

    线程对象=====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 {     public static void main(String[] args) throws Exception {

            Runnable run =() -> {                 for (int x = 0; x < 10; x++) {                     System.out.println(Thread.currentThread().getName() + "、x= " + x);                     try {                         // 暂缓执行                         Thread.sleep(100);                     } catch (Exception e) {                         // TODO Auto-generated catch block                         e.printStackTrace();                     }                 }             };             for(int num = 0;num < 5;num++){                 new Thread(run,"线程对象=====" + num).start();             }         } }  

              观察程序运行得出,发现有几个对象就有几个线程是一起进行休眠,而后一起进了自动唤醒,而其实是有差别,只是细微的时间差,每个对象还是分先后进行。

     

    3、线程中断

              在线程休眠中发现一个“InterruptedException”中断异常,就可以得知线程的休眠是可以被打断的,而这种打断是被其他线程完成的。

              中断执行方法:

     方法判断线程是否被中断 public boolean isInterrupted​() 中断线程执行 public void interrupt​()

              范例:观察线程的中断处理操作

    代码结果

    package cn.demos;

    public class Demo1 {     public static void main(String[] args) throws Exception {

            Thread thread = new Thread(() -> {             System.out.println("三天不睡觉的我需要睡觉补充精力");             // 休息10s             try {                 Thread.sleep(10000);             } catch (Exception e) {                 // 若线程被中断,会报一个中断异常                 System.out.println("睡觉被打扰,强行起床");             }         });         // 开始休息         thread.start();         // 出于人性化,可以让他先休息1s         thread.sleep(1000);         // 该判断线程是否中断 -------睡觉是否被打扰         if (!thread.isInterrupted()) {             // 若没被中断,执行中断操作-----若无人打扰睡觉,我就去手动晃醒他,不让他睡觉             System.out.println("在睡觉的人旁边跳广场舞");             thread.interrupt();         }     } }  

    三天不睡觉的我需要睡觉补充精力 在睡觉的人旁边跳广场舞 睡觉被打扰,强行起床

              结论:所有在执行的线程都是可以被中断的,而中断线程,都必须进行异常处理

     

    4、线程强制运行

              当满足于某些条件之后,某一个线程对象可以一直独占资源,一直到该线程的程序结束。

              1)范例:观察正常线程

    代码结果

    package cn.demos;

    public class Demo1 {     public static void main(String[] args) throws Exception {

            Thread thread = new Thread(() -> {             for (int x = 0; x < 10; x++) {                 System.out.println(Thread.currentThread().getName() + "执行、x=" + x);             }         }, "正常的线程");         thread.start();

            for (int y = 0; y < 10; y++) {             System.out.println("main的线程、y=" + 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 {     public static void main(String[] args) throws Exception {

            // 获得主线程         Thread mainThread = Thread.currentThread();         Thread thread = new Thread(() -> {             for (int x = 0; x < 100; x++) {                 // 当X>3时,只允许main线程执行,且执行完毕后才能运行其他线程                 if (x == 3) {                     // 执行强制线程                     try {                         mainThread.join();                     } catch (Exception e) {                         // TODO Auto-generated catch block                         e.printStackTrace();                     }                     ;                 }                 System.out.println(Thread.currentThread().getName() + "执行、x=" + x);             }         }, "正常的线程");

            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、线程礼让

              线程的礼让指的是将资源先让出去,让别的线程先使用资源。

              线程礼让方法:

    线程礼让yieldpublic static void yield​()

              范例:线程的礼让操作

    代码结果

    package cn.demos;

    public class Demo1 {     public static void main(String[] args) throws Exception {

            Thread thread = new Thread(() -> {             for (int x = 0; x < 100; x++) {                 if (x % 3 == 0) {                     // 线程礼让                     Thread.yield();                     System.out.println("!!!!正常线程礼让执行!!!");                 }                 try {                     Thread.sleep(100);                 } catch (Exception e) {                     // TODO Auto-generated catch block                     e.printStackTrace();                 }                 System.out.println(Thread.currentThread().getName() + "执行、x=" + x);             }         }, "正常的线程");

            thread.start();

            for (int y = 0; y < 100; y++) {             Thread.sleep(100);             System.out.println("main的线程、y=" + 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 1NORM_PRIORITY中等优先级 public static final int NORM_PRIORITY 5MAX_PRIORITY最高优先级 public static final int MAX_PRIORITY 10

              1)范例:观察优先级

    代码结果

    package cn.demos;

    public class Demo1 {     public static void main(String[] args) throws Exception {

            Runnable run = () -> {             for (int x = 0; x < 10; x++) {                 try {                     Thread.sleep(100);                 } catch (Exception e) {                     // TODO Auto-generated catch block                     e.printStackTrace();                 }                 System.out.println(Thread.currentThread().getName() + "执行,");             }         };         Thread threadA = new Thread(run, "线程对象A");         Thread threadB = new Thread(run, "线程对象B");         Thread threadC = new Thread(run, "线程对象C");         // 设置优先级         threadA.setPriority(Thread.MIN_PRIORITY);         threadB.setPriority(Thread.MIN_PRIORITY);         threadC.setPriority(Thread.MAX_PRIORITY);         // 执行         threadA.start();         threadB.start();         threadC.start();     } }  

    线程对象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 {     public static void main(String[] args) throws Exception {                  System.out.println(Thread.currentThread().getPriority());     } }  

    5

              由以上程序可以得出,主线程的优先级属于中等优先级,而默认的线程优先级也是中等优先级。

    Processed: 0.013, SQL: 8