《Java多线程编程核心技术(第2版)》 —1.2 使用多线程

举报
华章计算机 发表于 2020/02/08 13:11:17 2020/02/08
【摘要】 本节书摘来自华章计算机《Java多线程编程核心技术(第2版)》 一书中第1章,第1.2.1节,作者是高洪岩。

1.2 使用多线程

想学习一个技术就要“接近”它,所以本节首先通过一个示例来接触一下线程。

一个进程正在运行时至少会有一个线程在运行,这种情况在Java中也是存在的,这些线程在后台默默地执行,例如,调用public static void main()方法的线程就是这样的,而且它由JVM创建。

创建示例项目callMainMethodMainThread,并创建Test.java类,代码如下:

package test;

 

public class Test {

 

    public static void main(String[] args) {

        System.out.println(Thread.currentThread().getName());

    }

 

}

程序运行结果如图1-7所示。

image.png

在控制台输出的main其实就是一个名称为main的线程在执行main()方法中的代码。另外,需要说明一下,在控制台输出的main和main方法没有任何关系,它们仅仅是名字相同而已。

1.2.1 继承Thread类

Java的JDK开发包已经自带了对多线程技术的支持,通过它可以方便地进行多线程编程。实现多线程编程主要有两种方式:一种是继承Thread类,另一种是实现Runnable接口。

在学习如何创建新的线程前,先来看看Thread类的声明结构:

public class Thread implements Runnable

从上面的源代码中可以发现,Thread类实现了Runnable接口,它们之间具有多态关系,多态结构的示例代码如下:

Runnable run1 = new Thread();

Runnable run2 = new MyThread();

Thread t1 = new MyThread();

其实使用继承Thread类的方式创建新线程时,最大的局限是不支持多继承,因为Java语言的特点是单根继承,所以为了支持多继承,完全可以实现Runnable接口,即一边实现一边继承,但这两种方式创建线程的功能是一样的,没有本质的区别。

本节主要介绍第一种方式。创建名称为t1的Java项目,创建一个自定义的线程类MyThread.java,此类继承自Thread,并且重写run()方法。在run()方法中添加线程要执行的任务代码如下:

package com.mythread.www;

 

public class MyThread extends Thread {

@Override

    public void run() {

        super.run();

        System.out.println("MyThread");

    }

}

运行类代码如下:

package test;

 

import com.mythread.www.MyThread;

 

public class Run {

 

    public static void main(String[] args) {

        MyThread mythread = new MyThread();

        mythread.start();//耗时大

        System.out.println("运行结束!");//耗时小

    }

 

}

上面代码使用start()方法来启动一个线程,线程启动后会自动调用线程对象中的run()方法,run()方法里面的代码就是线程对象要执行的任务,是线程执行任务的入口。

程序运行结果如图1-8所示。

image.png

从图1-8的程序运行结果来看,MyThread.java类中的run()方法的执行时间相对于输出“运行结束!”的执行时间晚,因为start()方法的执行比较耗时,这也增加了先输出“运行结束!”字符串的概率。start()方法耗时的原因是执行了多个步骤,步骤如下。

1)通过JVM告诉操作系统创建Thread。

2)操作系统开辟内存并使用Windows SDK中的createThread()函数创建Thread线程对象。

3)操作系统对Thread对象进行调度,以确定执行时机。

4)Thread在操作系统中被成功执行。

以上4步完整地执行后所消耗的时间一定大于输出“运行结束!”字符串的时间。另外,main线程执行start()方法时不必等待4步都执行完毕,而是立即继续执行start()方法后面的代码,这4步会与输出“运行结束!”的代码一同执行,由于输出“运行结束!”耗时比较少,所以在大多数的情况下,先输出“运行结束!”,后输出“MyThread”。

但在这里,还是有非常非常小的、非常渺茫的机会能输出如下运行结果:

MyThread

运行结束!

输出上面的结果说明执行完整的start()方法的4步后,才执行输出“运行结束!”字符串的代码,这也说明线程执行的顺序具有随机性。然而由于输出这种结果的机会很小,使用手动的方式来重复执行“Run as”->“Java Application”难以重现,这时可以人为地制造这种输出结果,即在执行输出“运行结束!”代码之前先执行代码Thread.sleep(300),让run()方法有充足的时间来先输出“MyThread”,后输出“运行结束!”,示例代码如下:

package test;

 

import com.mythread.www.MyThread;

 

public class Run2 {

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

        MyThread mythread = new MyThread();

        mythread.start();

        Thread.sleep(200);

        System.out.println("运行结束!");

    }

}

在使用多线程技术时,代码的运行结果与代码的执行顺序或调用顺序是无关的。另外,线程是一个子任务,CPU以不确定的方式,或者说是以随机的时间来调用线程中的run()方法,所以先输出“运行结束!”和先输出“MyThread”具有不确定性。

如果多次调用start()方法,则出现异常Exception in thread “main” java.lang. Illegal-ThreadStateException。


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。