二:线程常用操作方法

时间: 2023-08-02 admin 互联网

二:线程常用操作方法

二:线程常用操作方法

          多线程的主要操作方法都在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
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 {
    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

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