线程的介绍

首先我们来了解一下线程是什么:

首先我们介绍一下程序是什么?程序就是我们编写的代码就叫程序,当我们程序运行的时候则称为进程,在我们现实生活中哪些用到了进程,就比如说我们qq,微信,百度网盘等等软件的使用,当它们在运行的时候,操作系统就会自动的给它们分配内存空间,那线程是什么,线程是由进程创建出来的,是进程的一个实体,一个进程可以拥有多个线程,线程分为两种一个是单线程,还有一个多线程。

单线程:同一时刻,只允许运行一个线程。

多线程:同一时刻,允许运行多个线程,比如qq,微信可以打开多个聊天框,百度网盘可以同时下载多个文件。

接下来我们来介绍两个新的概念:并发和并行

1.并发:同一时刻,多个任务交替执行,但是交换的速度会非常快,让我们感觉是在一块运行的一样,简单来说就像我们的大脑,在我们同时做多件事的时候大脑是迅速的来回切换的,单核cpu实现的多任务就是并发。

2.并行:同一时刻,多个任务同时进行,每个任务都有单独的cpu来执行,即多核cpu实现的多任务就是并行。

接下来我们就要来了解一下线程的使用方式:

首先我们来看一下体系图:

线程的介绍_第1张图片

这里我们可以得出创建线程的方式应该有两种:

一个是继承Thread类,还有一种就是实现Runnable接口。

我们先看一下继承Thread类的使用方法:

我们先来看一下实例代码:

public class ift{
    public static void main(String[] args) {
        Preson2 preson1 = new Preson2();
        preson1.start();
    }
}

class Preson2 extends Thread{
    int times= 0;
    @Override
    public void run(){
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("hello" + (times ++));
            if (times == 20){
                break;
            }
        }
    }
}

当我们继承Thread类的时候,我们必须要重写run()方法,否则的话,就会出现报错,但是我们在main方法中,发现我们创建对象之后并没有调用run方法而是调用了start()方法,这里我们来做一个解释,并且对源码进行分析:

线程的介绍_第2张图片

当我们调用start()方法的时候我们发现代码自动的调用到了start0()这个方法中,其实start0方法才会调用run()方法,但是它是如何调用的,这个调用过程我们是无法看到的,简单来说是start0()方法调用虚拟机,jvm就会自动的调用run()方法,底层是通过C/C++实现的,所以当我们执行start()方法的时候run方法就会被自动调用,但是run()方法并不是启动线程的方法,它只是编写了线程该执行任务,真正启动线程的还是start()方法(感兴趣的可以Degbug源码),接下来我们来看一下代码的运行示意图:

线程的介绍_第3张图片

public class ift extends Thread{
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Preson2 preson1 = new Preson2();
        preson1.start();
        int time = 0;
        while (true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("hi~" + (time ++));
            if (time == 10){
                break;
            }
        }
    }
}

class Preson2 extends Thread{
    int times= 0;
    @Override
    public void run(){
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("hello" + (times ++));
            if (times == 5){
                break;
            }
        }
    }
}

线程的介绍_第4张图片

这里我们发现主线程调用start方法后它是不会停止运行的,而是和子线程交替运行,只有两个线程的任务全部结束,才会退出程序。

第二种实现Runable接口的方式。

总所周知,Java的继承是单继承的方式,但是如果我们的类已经继承了其他父类这种情况我们就需要使用我们的接口来实现。

实际案例:

线程的介绍_第5张图片

这里我们发现当我们实现Runable接口后我们的start()方法就无法使用了,那我们该如何启动线程,我们来演示一下:

线程的介绍_第6张图片

这里我们相当于把它放在一个线程里包装一下,之后就可以使用start()方法。

我们来模拟一下start()调用过程:

class ThreadProxy implements Runnable {//你可以把 Proxy 类当做 ThreadProxy
    private Runnable target = null;//属性,类型是 Runnable
    @Override
    //这里就是一个模拟的一个run()方法,首先判断传入的对象是否为null,不为null的话就会直接调用传入对象的run()方法。
    public void run() {
        if (target != null) {
            target.run();//动态绑定(运行类型 Tiger)
        }
    }
    //我们创建线程调用的构造器,传入一个实现接口Runable的对象
    public ThreadProxy(Runnable target) {
        this.target = target;
    }
    //当我们调用start()方法的时候自动调用start0()方法
    public void start() {
        start0();//这个方法时真正实现多线程方法
    }
    //start0()会调用run()方法
    public void start0() {
        run();
    }
}

大概就是这么个意思,线程的其他具体内容后面再继续写。

你可能感兴趣的:(java,jvm,开发语言)