java中多线程并发并行线程与进程线程调度创建线程的方式

Posted 苦海123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中多线程并发并行线程与进程线程调度创建线程的方式相关的知识,希望对你有一定的参考价值。

多线程

多线程比单线程快,前面简单介绍过:集合如果是不安全的,那么它就是多线程的,了解多线程之前,先了解什么是并发和并行。

并发:指两个或多个事件在同一个时间段内发生。

并行:指两个或多个事件在同一时刻发生,这里强调同一时刻,并行的速度快于并发。

线程与进程:

进程:指一个内存中运行的应用程序,每个进程都有一个独立的空间,一个应用程序可以同时运行多个进程,进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个程序从创建到运行再到消亡的过程。

线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程,一个进程中是可以有多个线程的,这个应用程序可以称为多线程程序。简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。

CPU:计算机中央处理器,可以对数据进行计算,指挥计算机中软件和硬件工作。

线程调度

分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。

抢占调度:优选让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个线程执行,java使用的是抢占式调度。

创建线程类:

主线程:执行主方法(main)的线程被称作主线程。

单线程实现一个业务:

// 主线程:执行主方法(mian)的线程
// java默认是单线程的,从mian方法中开始,从上到下依次执行。
public class MainClass 
    public static void main(String[] args) 
        // 创建第一个对象:
        Person p1 = new Person("小明");
        p1.consoleHandle();

        // 创建第二个对象:
        Person p2 = new Person("小红");
        p2.consoleHandle();

        // 执行此程序,可以看到到上面部分从上到下依次执行:
        // 小明--0
        // 小明--1
        // 小红--0
        // 小红--1
        
        System.out.println(1 / 0); // 执行完上面的代码后,从这里开始报错Exception in thread "main"单线程程序中,抛出异常后,后面的代码将不能在执行,多线程的话可以将多个业务放到不同的线程中去,这样即使一个线程中抛出了异常,另一个线程也不会被影响到。
        System.out.println(5);
    

创建一个多线程程序

在lang包下有一个Thread类,代表线程,用来描述多个线程。java中创建线程有两种方式。

方式一:将类声明为Thread的子类,该子类应该重写Thread的run方法,,如:

定义一个多线程的类:

// 创建线程的第一种方式:创建Thread子类:
// 想要实现多线程,就要继承Thread类,其步骤:1.创建一个Thread子类、2.在该子类中重写run方法,设置线程任务(该线程要做什么)3.创建该类的实例对象 4.调用该实例的start方法开启新的线程(调用start方法会开辟新的线程,虚拟调用该线程的run方法)
// run执行的结果是两个线程并发的运行,当前线程(main线程,从调用返回给start方法)和另一个线程(创建的新线程,执行其run方法)
// start方法,一个线程只能调用一次,多次启动一个线程是非法的,特别是当线程已经结束执行后,不能再重新启动。

// 1.创建一个Thread的子类:
public class OneThreadClass extends Thread 
    // 2.重写run方法
    @Override
    public void run () 
        // run方法里面用来设置任务,这里还是以循环为例:
        for (int i = 0; i < 2; i++) 
            System.out.println("run1--" + i);
        
    ;

实例化一个多线的类:

public class TestOneThreadClass 
    public static void main(String[] args) 
        // 3.创建一个多线程类的实例:
        OneThreadClass ot = new OneThreadClass();
        // 4.调用该实例的start方法(start方法继承于Thread类)让其调用run方法来执行任务:
        ot.start();

        // 主线程也执行for
        for (int i = 0; i < 2; i++) 
            System.out.println("main--" + i);
        

        // 打印到控制台的结果如下:可以看到此时程序不是从上到下依次执行了,原因是这里是个多线程的,多个线程抢占cpu执行,同一优先级随机选择一个线程执行
        // main--0
        // run1--0
        // main--1
        // run1--1
    

程序执行图:

内存图:

Thread类的常用方法

创建一个继承Thread的类:

public class MyThread extends Thread 
    public MyThread() 
    

    // 4.修改线程名称还有一种方式就是通过构造方法调用super将名称传给super,注意重载格式是(String name)这个,如:
    public MyThread(String name) 
        super(name);
    

    @Override
    public void run () 
        // 1.Thread类的getName可以获取到线程的名称:
        String nm = getName();
        System.out.println(nm); // Thread-0, 每创建一个线程,并执行start方法后,会新增一个后面索引增加1的新线程

        // 2.Thread类的currentThread返回当前正在执行的线程对象的索引:
        System.out.println(Thread.currentThread()); // Thread[Thread-1,5,main] 和 Thread[Thread-0,5,main] Thread[线程001,5,main] Thread[线程003,5,main]
        System.out.println(Thread.currentThread().getName()); // Thread-0 和 Thread-1 线程001 线程003
    ;

使用继承了Thread类的类:

public class UseMyThread 
    public static void main(String[] args) 
        MyThread mt = new MyThread();
        mt.start();

        new MyThread().start();

        // 3.Thread类的setName(String name)设置线程的名字:
        MyThread mt2 = new MyThread();
        mt2.setName("线程001");
        mt2.start();

        // 4-2:对构造方法直接修改名称的测试:
        MyThread mt3= new MyThread("线程003");
        mt3.start();

        // 5.Thread的sleep(mills)方法,让线程休眠n毫秒后继续执行,如:正常一个循环会很快的执行完,此时用sleep给它休眠5000毫秒执行,就可以看到每各5秒钟打印一次:
        for (int i = 0; i < 10; i++) 
            System.out.println(i);
            try 
                // 本身会报异常,使用try/catch处理下即可
                Thread.sleep(5000);
             catch (InterruptedException e) 
                throw new RuntimeException(e);
            
        
    

创建多线程的第二种方式(推荐方式):

继承Runnable接口实现类:

// 1.创建一个Runnable接口的实现类
public class RunnableTmplClass implements Runnable 
    // 2.在实现类中重写Runnbale接口的run方法,设置线程任务
    @Override
    public void run() 
        for (int i = 0; i < 5; i++) 
            System.out.println(Thread.currentThread().getName() + "--" + i);
        
    

测试第二种方式实现多线程:

// 创建多线程的第二种方式:实现Runnable接口:
// Runnable接口应该由那些打算通过某一线程执行某实例的类来实现,类必须定义一个称为run的无参数方法。
// 实现步骤: 1.创建一个Runnable接口的实现类 2.在实现类中重写Runnbale接口的run方法,设置线程任务 3.创建一个Runnable接口的实现类对象 4.创建Thread类对象,构造方法中传递Runnable接口实现类对象 5.调用Thread类中的start方法,开启新的线程执行run方法
public class TwoThreadClass 
    public static void main(String[] args) 
        // 3.创建一个Runnable接口的实现类对象
        RunnableTmplClass rt = new RunnableTmplClass();
        // 4.创建Thread类对象,构造方法中传递Runnable接口实现类对象
        Thread td = new Thread(rt);
        // 5.调用Thread类中的start方法,开启新的线程执行run方法
        td.start();
        for (int i = 0; i < 5; i++) 
            System.out.println(Thread.currentThread().getName() + "--" + i);
        
    

前两种创建线程方式之间的区别:

1.实现Runnable接口创建多线程:

避免了单继承的局限性(一个类只能继承一个父类,如果类继承了Thread类后就无法再继承其他类了),但是实现了Runnable接口后还可以继承其他类,实现其他的接口。

2.增强了程序的扩展性,降低了程序的耦合性(解耦,实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离,可以实现多个Runnable接口实现类并设置run方法任务,给Thread类创建对象使用)。

匿名内部类方法实现线程的创建

// 匿名内部类方式实现线程的创建
// 匿名内部类的作用:简化代码,把子类继承父类,重写父类的方法,创建子类对象合在一起完成,把实现类实现接口,重写接口中的方法,创建实现类对象合成一步完成
// 匿名内部类的最终产物:子类、实现类对象,这个类没有名字
// 格式:new 父类/接口()重复父类/接口中的方法
public class ThreeThreadClass 
    public static void main(String[] args) 
       // 线程的父类是Thread
        new Thread()
            @Override
            public void run()
                for (int i = 0; i < 5; i++) 
                    System.out.println(Thread.currentThread().getName() + "----" + i);
                
            ;
        .start();
    

提示:本文图片等素材来源于网络,若有侵权,请发邮件至邮箱:810665436@qq.com联系笔者删除。
笔者:苦海

以上是关于java中多线程并发并行线程与进程线程调度创建线程的方式的主要内容,如果未能解决你的问题,请参考以下文章

java 多线程问题 真的提高了效率吗?

聊聊线程模型:用户线程和内核线程

4-5 《Java中多线程重点》——继承Thread实现Runnable死锁线程池Lambda表达式

并发编程解惑之线程

java并发编程基础——线程的创建

java 多线程怎么深入?