Java并发之线程

来源:互联网 发布:mysql集群监控 编辑:程序博客网 时间:2024/05/19 12:39

   在前面我们介绍的一些内容中,我们的程序都是一条执行流,一步一步的执行。但其实这种程序对我们计算机的资源的使用上是低效的。例如:我们有一个用于计算的程序,主程序计算数据,在计算的过程中每得到一个结果就需要将其保存到外部磁盘上,那么难道我们的主程序每次都要停止等待CPU将结果保存到磁盘之后,再继续完成计算工作吗?要知道磁盘的速度可是巨慢的(相对内存而言),我们如果能分一个线程去完成磁盘的写入工作,主线程还是继续计算的话,是不是效率更高了呢?其实,并发就是这样的一种思想,使用时间片分发给各个线程CPU的使用时间,给人感觉好像程序在同时做多个事情一样,这样做的好处主要在于它能够对我们整个的计算机资源有一个充分的利用,在多个线程竞争计算机资源不冲突的前提下,充分的利用我们的资源。本篇文章首先来介绍并发的最基本的内容-----线程。主要涉及以下一些内容:

  • 定义线程的两种不同的方法及它们之间的区别
  • 线程的几种不同的状态及其区别
  • Thread类中的一些线程属性和方法
  • 多线程遇到的几个典型的问题

     一、创建一个线程
     首先我们看创建一个线程的第一种方式,继承Thread类并重写其run方法。

public class MyThread extends Thread {    @Override    public void run(){        System.out.println("this is mythread");    }}

现在我们来看看在主程序中如何启动我们自定义的线程:

public static void main(String[] args) {    Thread myThread = new MyThread();    myThread.start();}

我们首先构建一个Thread实例,调用其start方法,调用该方法会为线程分配其所必须的堆栈资源,计数器,时间片等,并在该方法的结束时刻调用我们重写的run方法,完成线程的启动。

但是在Java中类是单继承的,也就是如果某个类已经有了父类,那么它就不能被定义成线程类。当然,Java中也提供了第二种方法来定义一个线程类,这种方式实际上更加的接近本质一些。通过继承接口Runnable并在其内部重写一个run方法。

public class MyThread implements Runnable{    @Override    public void run(){        System.out.println("this is mythread");    }}

启动线程的方式和上一种略微有点不同,但是本质上都是一样的。

public static void main(String[] args) {        Thread myThread = new Thread(new MyThread());        myThread.start();    }

这里我们利用Thread的一个构造函数,传入一个实现了Runnable接口的参数。下面我们看看这个构造函数的具体实现:

public Thread(Runnable target) {        init(null, target, "Thread-" + nextThreadNum(), 0);    }

调用init方法对线程的一些状态优先级等做一个初始化的操作,我们顺便看看使用第一种方式创建线程实例的那个无参的构造函数:

public Thread() {        init(null, null, "Thread-" + nextThreadNum(), 0);    }

可以看到,两个构造函数的内部调用的是同一个方法,只是传入的参数不同而已。所以他们之间的区别就在于初始化的时候这个Runnable参数是否为空,当然这个参数的用处在run方法中也可以看出来:

@Overridepublic void run() {    if (target != null) {        target.run();    }}

如果我们使用第二种方式构建Thread实例,那么此处的target肯定不会是null,自然会调用我们重写的run方法。如果使用的是第一种方式构建的Thread实例,那么就不会调用上述的run方法,而是调用的我们重写的Thread的run方法,所以从本质上看,两种方式的底层处理都是一样的。

这就是创建一个线程类并启动该线程的两种不同的方式,表面上略有不同,但是实际上都是一样的调用init方法完成初始化。对于启动线程的start方法的源码,由于调用本地native方法,暂时并不易解释,有兴趣的可以使用jvm指令查看本地方法的实现以了解整个线程从分配资源到调用run方法启动的全过程。

原创粉丝点击