(四)多线程:控制线程

 Java的线程支持提供了一些便捷的工具方法,通过这些方法可以很好地控制线程的执行。

1.join线程

 Thread提供了让一个线程等待另一个线程完成的方法——join()方法。当在某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到被join()方法加入的join()线程执行完毕为止。
 join()方法通常由使用线程的程序调用,以将大问题划分成许多小问题,每个小问题分配一个线程。当所有的小问题都得到处理后,再调用主线程来进一步操作。
示例代码:

public class JoinThread extends Thread {

    public JoinThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("线程名:" + getName() + " i:" + i);
        }
    }

    public static void main(String[] args) {
        new JoinThread("新线程").start();
        for (int i = 0; i < 100; i++) {
            if (i == 20) {
                JoinThread jt = new JoinThread("被join的线程");
                jt.start();
                try {
                    jt.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程名:" + Thread.currentThread().getName() + " i:" + i);
        }
    }
}

运行结果:

线程名:main i:0
线程名:main i:1
线程名:新线程 i:0
线程名:新线程 i:1
线程名:main i:2
线程名:main i:3
线程名:main i:4
线程名:新线程 i:2
线程名:main i:5
线程名:新线程 i:3
线程名:main i:6
线程名:新线程 i:4
线程名:main i:7
线程名:main i:8
线程名:main i:9
线程名:main i:10
线程名:新线程 i:5
线程名:新线程 i:6
线程名:新线程 i:7
线程名:新线程 i:8
线程名:新线程 i:9
线程名:新线程 i:10
线程名:新线程 i:11
线程名:main i:11
线程名:main i:12
线程名:main i:13
线程名:main i:14
线程名:main i:15
线程名:main i:16
线程名:main i:17
线程名:新线程 i:12
线程名:main i:18
线程名:新线程 i:13
线程名:main i:19
线程名:新线程 i:14
线程名:新线程 i:15
线程名:新线程 i:16
线程名:新线程 i:17
线程名:新线程 i:18
线程名:新线程 i:19
线程名:新线程 i:20
线程名:新线程 i:21
线程名:新线程 i:22
线程名:新线程 i:23
线程名:新线程 i:24
线程名:新线程 i:25
线程名:新线程 i:26
线程名:新线程 i:27
线程名:新线程 i:28
线程名:新线程 i:29
线程名:新线程 i:30
线程名:新线程 i:31
线程名:被join的线程 i:0
线程名:新线程 i:32
线程名:被join的线程 i:1
线程名:被join的线程 i:2
线程名:新线程 i:33
线程名:新线程 i:34
线程名:被join的线程 i:3
线程名:新线程 i:35
线程名:被join的线程 i:4
线程名:新线程 i:36
线程名:被join的线程 i:5
线程名:新线程 i:37
线程名:被join的线程 i:6
线程名:新线程 i:38
线程名:新线程 i:39
线程名:新线程 i:40
线程名:新线程 i:41
线程名:被join的线程 i:7
线程名:新线程 i:42
线程名:被join的线程 i:8
线程名:被join的线程 i:9
线程名:被join的线程 i:10
线程名:被join的线程 i:11
线程名:被join的线程 i:12
线程名:被join的线程 i:13
线程名:被join的线程 i:14
线程名:被join的线程 i:15
线程名:新线程 i:43
线程名:被join的线程 i:16
线程名:被join的线程 i:17
线程名:被join的线程 i:18
线程名:被join的线程 i:19
线程名:被join的线程 i:20
线程名:被join的线程 i:21
线程名:被join的线程 i:22
线程名:被join的线程 i:23
线程名:被join的线程 i:24
线程名:被join的线程 i:25
线程名:被join的线程 i:26
线程名:新线程 i:44
线程名:被join的线程 i:27
线程名:新线程 i:45
线程名:被join的线程 i:28
线程名:新线程 i:46
线程名:被join的线程 i:29
线程名:新线程 i:47
线程名:被join的线程 i:30
线程名:新线程 i:48
线程名:被join的线程 i:31
线程名:新线程 i:49
线程名:被join的线程 i:32
线程名:新线程 i:50
线程名:被join的线程 i:33
线程名:新线程 i:51
线程名:被join的线程 i:34
线程名:新线程 i:52
线程名:被join的线程 i:35
线程名:新线程 i:53
线程名:新线程 i:54
线程名:被join的线程 i:36
线程名:被join的线程 i:37
线程名:被join的线程 i:38
线程名:新线程 i:55
线程名:新线程 i:56
线程名:新线程 i:57
线程名:新线程 i:58
线程名:新线程 i:59
线程名:新线程 i:60
线程名:被join的线程 i:39
线程名:新线程 i:61
线程名:新线程 i:62
线程名:新线程 i:63
线程名:新线程 i:64
线程名:新线程 i:65
线程名:被join的线程 i:40
线程名:新线程 i:66
线程名:被join的线程 i:41
线程名:新线程 i:67
线程名:被join的线程 i:42
线程名:新线程 i:68
线程名:被join的线程 i:43
线程名:新线程 i:69
线程名:被join的线程 i:44
线程名:被join的线程 i:45
线程名:新线程 i:70
线程名:被join的线程 i:46
线程名:被join的线程 i:47
线程名:新线程 i:71
线程名:被join的线程 i:48
线程名:新线程 i:72
线程名:被join的线程 i:49
线程名:新线程 i:73
线程名:被join的线程 i:50
线程名:新线程 i:74
线程名:被join的线程 i:51
线程名:新线程 i:75
线程名:被join的线程 i:52
线程名:新线程 i:76
线程名:被join的线程 i:53
线程名:被join的线程 i:54
线程名:被join的线程 i:55
线程名:被join的线程 i:56
线程名:被join的线程 i:57
线程名:被join的线程 i:58
线程名:被join的线程 i:59
线程名:被join的线程 i:60
线程名:被join的线程 i:61
线程名:新线程 i:77
线程名:被join的线程 i:62
线程名:新线程 i:78
线程名:被join的线程 i:63
线程名:新线程 i:79
线程名:被join的线程 i:64
线程名:新线程 i:80
线程名:新线程 i:81
线程名:被join的线程 i:65
线程名:新线程 i:82
线程名:新线程 i:83
线程名:新线程 i:84
线程名:新线程 i:85
线程名:新线程 i:86
线程名:新线程 i:87
线程名:新线程 i:88
线程名:新线程 i:89
线程名:新线程 i:90
线程名:新线程 i:91
线程名:新线程 i:92
线程名:新线程 i:93
线程名:新线程 i:94
线程名:新线程 i:95
线程名:新线程 i:96
线程名:新线程 i:97
线程名:新线程 i:98
线程名:新线程 i:99
线程名:被join的线程 i:66
线程名:被join的线程 i:67
线程名:被join的线程 i:68
线程名:被join的线程 i:69
线程名:被join的线程 i:70
线程名:被join的线程 i:71
线程名:被join的线程 i:72
线程名:被join的线程 i:73
线程名:被join的线程 i:74
线程名:被join的线程 i:75
线程名:被join的线程 i:76
线程名:被join的线程 i:77
线程名:被join的线程 i:78
线程名:被join的线程 i:79
线程名:被join的线程 i:80
线程名:被join的线程 i:81
线程名:被join的线程 i:82
线程名:被join的线程 i:83
线程名:被join的线程 i:84
线程名:被join的线程 i:85
线程名:被join的线程 i:86
线程名:被join的线程 i:87
线程名:被join的线程 i:88
线程名:被join的线程 i:89
线程名:被join的线程 i:90
线程名:被join的线程 i:91
线程名:被join的线程 i:92
线程名:被join的线程 i:93
线程名:被join的线程 i:94
线程名:被join的线程 i:95
线程名:被join的线程 i:96
线程名:被join的线程 i:97
线程名:被join的线程 i:98
线程名:被join的线程 i:99
线程名:main i:20
线程名:main i:21
线程名:main i:22
线程名:main i:23
线程名:main i:24
线程名:main i:25
线程名:main i:26
线程名:main i:27
线程名:main i:28
线程名:main i:29
线程名:main i:30
线程名:main i:31
线程名:main i:32
线程名:main i:33
线程名:main i:34
线程名:main i:35
线程名:main i:36
线程名:main i:37
线程名:main i:38
线程名:main i:39
线程名:main i:40
线程名:main i:41
线程名:main i:42
线程名:main i:43
线程名:main i:44
线程名:main i:45
线程名:main i:46
线程名:main i:47
线程名:main i:48
线程名:main i:49
线程名:main i:50
线程名:main i:51
线程名:main i:52
线程名:main i:53
线程名:main i:54
线程名:main i:55
线程名:main i:56
线程名:main i:57
线程名:main i:58
线程名:main i:59
线程名:main i:60
线程名:main i:61
线程名:main i:62
线程名:main i:63
线程名:main i:64
线程名:main i:65
线程名:main i:66
线程名:main i:67
线程名:main i:68
线程名:main i:69
线程名:main i:70
线程名:main i:71
线程名:main i:72
线程名:main i:73
线程名:main i:74
线程名:main i:75
线程名:main i:76
线程名:main i:77
线程名:main i:78
线程名:main i:79
线程名:main i:80
线程名:main i:81
线程名:main i:82
线程名:main i:83
线程名:main i:84
线程名:main i:85
线程名:main i:86
线程名:main i:87
线程名:main i:88
线程名:main i:89
线程名:main i:90
线程名:main i:91
线程名:main i:92
线程名:main i:93
线程名:main i:94
线程名:main i:95
线程名:main i:96
线程名:main i:97
线程名:main i:98
线程名:main i:99

2.后台线程

 有一种线程,它时在后台运行的,它的任务是为其他的线程提供服务,这种线程被称为“后台线程”(Daemon THread),又称为“守护线程”或“精灵线程”。JVM的垃圾回收线程就是典型的后台线程。
 后台线程有个特征:如果所有的前台线程都死亡,后台线程会自动死亡。
 调用Thread对象的setDaemon(true)方法就可将指定线程设置成后台线程。
 要将某个线程设置为后台线程,必须在线程启动之前设置,否则会引发异常。

3.线程睡眠:sleep

 如果需要让当前正在执行的线程暂停一段时间,并进入阻塞状态,则可以通过调用Thread类的静态sleep()方法来实现。
 当当前线程调用sleep()方法进入阻塞状态后,在其睡眠时间段内,该线程不会获得执行机会,即使系统中没有其他可执行的线程,处于sleep()中的线程也不会执行,因此sleep()方法常用来暂停程序的执行。

4.线程让步:yield

 yield()方法是一个和sleep()方法有点相似的方法,它也是Thread类提供的一个静态方法,它也可以让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程转入就绪状态。yield()只是让当前线程暂停一下,让系统的线程调度器重新调度一次。完全可能的情况是:当某个线程调用了yield()方法暂停之后,线程调度器又将其调度出来重新执行。(实际上,当某个线程调用了yield()方法暂停后,只是优先级与当前线程相同,或者优先级比当前线程更高的处于就绪状态的线程才会获得执行的机会)

划重点(笔试高频出现):sleep()方法和yield()方法的区别:

  • sleep()方法暂停后当前线程后,会给其他线程执行机会,不会理会其他线程的优先级;但yield()方法只会给优先级相同,或者优先级更高的线程执行机会。
  • sleep()方法会将线程转入阻塞状态,直到经过阻塞时间才会转入就绪状态;而yield()不会将线程转入阻塞状态,它只是强制当前线程进入就绪状态。因此完全有可能某个线程调用yield()方法暂停之后,立即获得处理器资源被执行。
  • sleep()方法声明抛出InterruptedException异常,所以调用sleep()方法是要么捕捉该异常,要么显式声明抛出该异常;而yield()方法则没有声明抛出任何异常。
  • sleep()方法比yield()方法又更好的移植性,通常不建议使用yield()方法来控制并发线程当然执行。

5.改变线程优先级

 每个线程执行时都具有一定的优先级,优先级高的线程获得较多的执行机会,而优先级低的线程则获得较少的执行机会;
 Thread类提供了setPriority(int newPriority)来设置指定线程的优先级;

文章内容均取自《疯狂Java讲义-李刚》一书中多线程章节。截取重要知识点作为笔记记录,方便自己回顾。

原文地址:https://www.cnblogs.com/everyingo/p/12799352.html