← 返回首页
JavaSE系列教程(六十二)
发表时间:2020-02-09 12:07:39
讲解线程的命名、休眠和join方法使用。

1.线程的命名

可以通过Thread的构造方法或者setName方法给线程命名。

 Thread th = new Thread(new MyRunnable(),"线程名字");
 Thread th = new Thread(new MyRunnable());
 th.setName("线程名字");

使用Thread.currentThread().getName()获得当前线程的名字。

例如:在主方法中启动一个线程计算1+2+3+…+100的求和。程序的入口方法main方法是主线程(main线程),计算求和是另一个子线程,所以程序运行时是两个线程同时执行。

代码如下:

class MyRunnable implements Runnable{

    @Override
    public void run() {
        long result=0;
        for(int i=1;i<=100;i++){
            result += i;
            System.out.println(Thread.currentThread().getName() + ",i=" + i);//获取当前线程的名字
            try {
                Thread.sleep(50); //当前线程休眠50毫秒

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("result=" + result);
    }
}


public class Test {
    public static void main(String[] args) throws InterruptedException {

        Thread th = new Thread(new MyRunnable());
        th.setName("我的线程1");//给线程命名
        th.start();//启动线程

        for(int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+",i=" + i);
            Thread.sleep(200);
        }
    }
}

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

从执行结果可以看出是两个线程交替执行,分别是主线程main,和子线程'我的线程1'。

2.线程的休眠

使用Thread.sleep(long mills);使当前线程休眠,进入阻塞状态(暂停执行),如果线程在睡眠状态被中断,将会抛出IterruptedException中断异常。 主要方法如下:

sleep(long millis) 线程睡眠 millis 毫秒 sleep(long millis, int nanos) 线程睡眠 millis 毫秒 + nanos 纳秒

注意:

1.sleep()方法是Thread类的静态方法,如果调用线程对象.sleep()方法并不是该线程就休眠,反正在哪一个线程里面执行了sleep()方法哪一个线程就休眠。

2.线程睡眠到期自动苏醒,并返回到可运行状态(就绪),并不是运行状态。

实例: 下面以一个倒计时的功能来进一步说明sleep()方法的使用。

public class Test {

    public static void countDown(long mills) {
        Date endDate = new Date(System.currentTimeMillis() + mills);
        long endTime = endDate.getTime();

        while (true) {
            System.out.println(new SimpleDateFormat("hh:mm:ss").format(endDate));
            //下一秒时间
            endDate = new Date(endDate.getTime() - 1000);
            //休眠一秒钟
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (endTime - endDate.getTime() > mills) {
                break;
            }
        }
    }



    public static void main(String[] args) throws InterruptedException {

        Test.countDown(10000); ////倒计时10秒
    }
}

运行结果:
11:57:51
11:57:50
11:57:49
11:57:48
11:57:47
11:57:46
11:57:45
11:57:44
11:57:43
11:57:42
11:57:41

3.join 方法

当某个线程调用方法时,这个方法会挂起调用线程,直到被调用线程结束执行,调用线程才会继续执行。也就是当前线程要等待别的线程执行完毕才能继续执行。

实例: 吃中饭,妈妈开始做饭。 做饭的时候发现没有酱油了,没有辣椒了。 该妈妈有两个儿子,大儿子,小儿子。大儿子买酱油,小儿子买辣椒。妈妈在家等,等酱油和辣椒都买回来之后,开始做饭。如何用多线程来描述这个故事呢?

public class MotherDemo {

    public static void main(String[] args) {

        System.out.println("开始做午饭了...");
        ////////这个时候,发现没有酱油了,没有辣椒了。
        //兵分两路,派出两个线程,一个负责买辣子,一个负责买辣椒。

        Runnable bigSon = ()->{
            for(int i=0;i<10;i++){
                System.out.println("大儿子买酱油中...");
                try {
                    Thread.sleep(100); // 当前线程处于休眠状态。
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };


        Runnable smallSon = ()->{
            for(int i=0;i<10;i++){
                System.out.println("小儿子买辣椒中...");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        Thread bigSonTh = new Thread(bigSon,"大儿子线程");
        Thread smallSonTh = new Thread(smallSon,"小儿子线程");

        bigSonTh.start();
        smallSonTh.start();

        try{
            //妈妈线程中调用了join方法,分别等待两个儿子线程结束
            bigSonTh.join();
            smallSonTh.join();

        }catch(Exception ex){
            ex.printStackTrace();
        }

        System.out.println("酱油和辣椒都买回来了,继续做饭...");
        System.out.println("香喷喷的午饭做好了,请享用!");

    }
}

运行结果:
开始做午饭了...
小儿子买辣椒中...
大儿子买酱油中...
小儿子买辣椒中...
大儿子买酱油中...
小儿子买辣椒中...
大儿子买酱油中...
大儿子买酱油中...
小儿子买辣椒中...
小儿子买辣椒中...
大儿子买酱油中...
大儿子买酱油中...
小儿子买辣椒中...
大儿子买酱油中...
小儿子买辣椒中...
小儿子买辣椒中...
大儿子买酱油中...
小儿子买辣椒中...
大儿子买酱油中...
大儿子买酱油中...
小儿子买辣椒中...
酱油和辣椒都买回来了,继续做饭...
香喷喷的午饭做好了,请享用!

小结:

1).可以通过Thread的构造方法或者setName方法给线程命名。

2).使用Thread.sleep(long mills);使当前线程休眠,进入阻塞状态(暂停执行),如果线程在睡眠状态被中断,将会抛出IterruptedException中断异常。线程睡眠到期自动苏醒,并返回到可运行状态(就绪),并不是运行状态。

3).当某个线程调用方法时,这个方法会挂起调用线程,直到被调用线程结束执行,调用线程才会继续执行。