详解创建Java多线程的两种方式

      多线程的创建与使用是java工作学习中常见的内容,一直对多线程怀有神秘感,今天就把自己对多线程的理解分享给大家,供学习交流。

      进程:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。   

      线程:是程序中一个单一的顺序控制流程,是cpu调度的最小单位。

      多线程:在单个程序中同时运行多个线程完成不同的工作,称为多线程。

      线程的生命周期有五个阶段:新建(new Thread)、就绪(runnable)、运行(running)、堵塞(blocked)、死亡(dead)。

      新建(new Thread):当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。

      就绪(runnable):线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。

      运行(running):线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。

      堵塞(blocked):由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。

      死亡(dead):当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。

      在java中创建多线程一般有两种方式是,一种是继承Thread类,并重写run()方法;另一种是实现Runnable接口,并重写run()方法。

      第一种:继承Thread类

package com.xyfer;

public class ThreadDemo extends Thread(){

    @Override
    public void run(){
        for(int i=0;i<5;i++){
            System.out.println("继承Thread类第"+i+"次打印");
        }
    }
}

   测试类进行多线程测试,

package com.xyfer;

public class ThreadTest {
    public static void main (String[] args) {
        ThreadDemo test1 = new ThreadDemo();
        ThreadDemo test2 = new ThreadDemo();
        test1.start();
        test1.start();
    }
}

控制台打印:

继承Thread类第0次打印

继承Thread类第0次打印

继承Thread类第1次打印

继承Thread类第1次打印

继承Thread类第2次打印

继承Thread类第2次打印

继承Thread类第3次打印

继承Thread类第3次打印

继承Thread类第4次打印

继承Thread类第4次打印

再执行一次:

继承Thread类第0次打印

继承Thread类第0次打印

继承Thread类第1次打印

继承Thread类第1次打印

继承Thread类第2次打印

继承Thread类第3次打印

继承Thread类第2次打印

继承Thread类第4次打印

继承Thread类第3次打印

继承Thread类第4次打印

程序启动运行main时,java虚拟机启动一个进程,主线程在main()方法被调用的时候创建,main()方法运行在主线程中,随着main()方法中的两个对象的start()方法调用,另外两个线程也被启动,这样,整个程序就在多线程下运行了。

多次运行,从控制台打印结果可以看出,多线程并不是按顺序执行代码的,而是随机执行的,操作系统随机在多个线程之间切换。start()方法调用后并不是立即执行相应线程代码,而是把线程代码变成可执行状态,等待操作系统随机执行。

      第二中:实现Runnable接口

package com.xyfer;

public class ThreadRunnable implements Runnable(){

    @Override
    public void run(){
        for(int i=0;i<5;i++){
            System.out.println("实现Runnable接口第"+i+"次打印");
        }
    }
}

测试类进行多线程测试:(通过Thread的构造方法传入Runnable接口的实现类创建Thread类实例调用start()方法启动线程)

package com.xyfer;

public class ThreadTest {
    public static void main (String[] args) {
        new Thread(new ThreadRunnable()).start();
        new Thread(new ThreadRunnable()).start();
    }
}

控制台输出结果:

实现Runnable接口第0次打印

实现Runnable接口第0次打印

实现Runnable接口第1次打印

实现Runnable接口第1次打印

实现Runnable接口第2次打印

实现Runnable接口第2次打印

实现Runnable接口第3次打印

实现Runnable接口第3次打印、

此时多线程仍然是随机执行线程,多执行几次程序就会发现控制台打印结果顺序不一样。

多线程中的join()方法

下面介绍一下多线程中的join()方法,很多情况下,主线程启动了子线程,但是通常子线程要做大量的耗时工作,因此会出现主线程先于子线程执行结束。但是有时候主线程是需要子线程的执行结果的,这时候就需要使用多线程的join()方法来控制主线程等待子线程执行完毕后再结束主线程。

以继承Thread类为例:

package com.xyfer;

public class ThreadDemo extends Thread(){

    @Override
    public void run(){
        for(int i=0;i<5;i++){
            System.out.println("继承Thread类第"+i+"次打印");
        }
    }
}

测试类:

package com.xyfer;

public class ThreadTest {
    public static void main (String[] args) {
        System.out.println("主线程开启。");
        ThreadDemo test1 = new ThreadDemo();
        ThreadDemo test2 = new ThreadDemo();
        test1.start();
        test1.start();
        System.out.println("主线程结束。");
    }
}

控制台打印结果:

主线程开启。

主线程结束。

继承Thread类第0次打印

继承Thread类第1次打印

继承Thread类第2次打印

继承Thread类第3次打印

继承Thread类第4次打印

继承Thread类第0次打印

继承Thread类第1次打印

继承Thread类第2次打印

继承Thread类第3次打印

继承Thread类第4次打印

从控制台打印结果来看,主线程先于子线程执行结束。使用join()方法后就能保证主线程在子线程之后执行结束。

package com.xyfer;

public class ThreadTest {
    public static void main (String[] args) {
        System.out.println("主线程开启。");
        ThreadDemo test1 = new ThreadDemo();
        ThreadDemo test2 = new ThreadDemo();
        test1.start();
        test1.start();
        try {
            test1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            test2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("主线程结束。");
    }
}

控制台打印结果:

主线程开启。

继承Thread类第0次打印

继承Thread类第1次打印

继承Thread类第2次打印

继承Thread类第3次打印

继承Thread类第4次打印

继承Thread类第0次打印

继承Thread类第1次打印

继承Thread类第2次打印

继承Thread类第3次打印

继承Thread类第4次打印

主线程结束。

从控制台打印结果可以看出,join()方法能保证主线程在子线程执行结束之后再执行结束。

猜你喜欢

转载自blog.csdn.net/xyfer1018/article/details/82799048
今日推荐