入门Java编程的知识点—>多线程(day15)

  • 了解掌握多线程的意义?
  • 重点掌握多线程的创建方式?如何使用?

多线程概述

操作系统分类
单任务处理

        一个任务完成后才能进行下一个任务。

-- 缺点:长时间运行的任务会阻止其他任务执行,有Bug造成无限循环,会使整个计算机停止工作。

多任务处理:CPU分时操作,每个任务看似同时运行。

-- OS将时间划分为很多时间片段(时间片),尽可能均匀分配给正在运行的程序,获取时间片的程序得以执行,其他则等待。而CPU则在这些程序上来回切换。实际所有程序都是走走停停,由于切换频密,看似都在运行,这种现象叫并发,但不是绝对意义上的“同时”发生。

进程

应用程序的一个运行实例,包含程序所需资源的内存区域,是操作系统进行资源分配的单元,进程隔离了正在执行的不同程序。

优点:进程间相互独立,互不影响。

Java程序的运行过程
  1. 通过eclipse(java命令)运行一个Java程序,java命令会启动JVM(java虚拟机),等于启动了一个应用程序,也就是启动了一个进程。
  2. 该进程会自动启动一个“主线程”,然后主线程去调用某个类的 main 方法,所以 main 方法运行在主线程中。在此之前的所有程序代码都是按照顺序依次调用的,都是单线程的。

如果希望程序中实现多段程序代码交替执行的效果,则需要创建多线程程序。

为什么要使用多线程?
  • 单线程程序执行时都只有一条顺序执行流,如果程序执行某行代码时遇到了阻塞(比如:抛异常),那么程序的运行将会停滞在这一行,其他代码将会无法执行!
  • 这就像去银行办理业务,只有1个业务窗口(单线程),所有的客户都需要在一个窗口排队办理业务,如果业务员在为某一个客户办理业务时,花费了很长时间,那么将会导致后面的客户等待很长时间,这样处理业务的效率也是非常低的。
  • 但如果银行为了提高效率,同时开放了5个窗口(多线程),客户可以分布在这5个窗口分别办理业务,即使某一个窗口在为个别客户办理业务时花费了很长时间,但不影响其他窗口办理业务的进度。

多线程理解起来其实非常简单:

  • 单线程的程序只有一个顺序执行流。
  • 多线程的程序则可以包括多个顺序执行流,多个顺序流之间互不干扰。
[并行]和[并发]的区别

1)并行执行指在同一时刻,有多条指令在多个处理器上同时执行;

2)并发执行指在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。

多线程的特性

随机性

多线程的程序在执行时,在某一时间点具体执行哪个线程是不确定的,可以确定的是某一个时间点只有一个线程在执行(单核CPU)。

虽然我们感觉这些线程像是在同时运行,实际上是因为CPU在快速切换轮流执行这些线程,由于切换速度是纳秒级别的,所以我们感觉不到。

如何实现多线程

由于线程是依赖进程存在的,因此首先需要创建一个进程,但进程是操作系统创建的,而Java程序是不能直接调用系统功能的。但Java可以去调用C或C++写好的程序去创建进程从而实现多线程程序。

在Java中要想实现多线程操作有两种方式,一种是继承Thread类,另一种是实现Runnable接口。接下来针对这两种创建多线程的方式分别进行讲解。

1. 继承Thread类

Thread类概述

Thread类是在java.lang包中定义的类

JavaSE规范中规定,一个类只要继承了Thread类,此类就是多线程的子类。

在Thread子类中,必须重写该类的run()方法,此方法为线程的主体。

  • 通过继承Thread类创建线程

接下来通过案例演示<通过继承Thread类的方式实现多线程>

下面创建线程,并测试主线程和创建的新线程(子线程)交替执行的效果

代码实现如下:

package thread;

/**
 * 多线程
 * 多线程可以并发执行多个任务
 * 线程的第一种创建方式
 * 继承Thread类,并且重写其中的run方法,在run方法中定义需要并发执行的任务代码
 */
public class ThreadDemo1 {
    public static void main(String[] args) {
        //4.创建线程类的实例
        Thread t1 = new MyThread01();
        Thread t2 = new MyThread02();
        //5.启动线程要调用start()方法
        /*
         * 注意:启动线程是调用 start方法,并非直接调用run方法,当调用start方法时,
         * 线程会纳入线程调度器中统一被管理,一旦线程分配CPU的时间片,
         * 于是就开始自动执行run方法
         */
        t1.start();
        t2.start();
    }
}

/*
 * 这种创建线程的方式的优点是: 结构简单,便于匿名内部类创建
 * 缺点:
 * 1.java是单继承,也就是使用这种方式,当前类就不能再继承别的类了,无法复用其他方法,
 * 对于实际开发会有很多的不便
 * 2.定义线程时,重写了run方法,直接将任务定义在了线程里,导致线程与任务存在必然的耦合关系,
 * 不利于线程的重用
 */
//1.创建一个线程类,继承Thread类
class MyThread01 extends Thread{
    //2.重写Thread类中的run方法
    @Override //可以编译器自动校验重写的方法体是否符合语法
    public void run() {
        //3.run方法中要书写线程执行的代码内容
        for(int i=0;i<1000;i++){
            System.out.println("第"+i+"次说:你是谁啊!?");
        }
    }
}
class MyThread02 extends Thread{
    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            System.out.println("第"+i+"次说:开门,查水表的!!!");
        }
    }
}

从上面的运行结果可以看出,main方法(主线程)和run方法(子线程)中的两个for循环中的输出语句交替执行了,说明通过集成Thread类实现了多线程。

(如果没有测试出主线程和子线程交替执行的效果,可以多测试几次!)

2. 实现Runnable接口

Runnable接口概述

通过继承Thread类实现了多线程,但是这种方式有一定的局限性。因为Java中只支持单继承,一个类一旦继承了某个父类就无法再继承Thread类,例如猫类Cat继承了动物类Animal,就无法通过继承Thread类实现多线程。

为了克服这种弊端,在Thread类中提供了两个构造方法:

public Thread(Runnable target)

public Thread(Runnable target,String name)

这两个构造方法都可以接收Runnable的子类实例对象,这样创建的线程将调用实现了Runnable接口类中的run()方法作为运行代码,而不需要调用Thread类的run()方法,所以就可以依靠Runnable接口的实现类启动多线程。

  • 通过实现Runnable接口实现多线程

接下来通过案例演示<通过实现Runnable接口的方式实现多线程>

下面创建线程,并测试主线程和创建的新线程(子线程)交替执行的效果

代码实现如下:

package thread;

/**
 * 第二种创建线程的方式:
 * 实现Runnable接口,定义线程任务
 */
public class ThreadDemo2 {
    public static void main(String[] args) {
        //4.实例化线程要实现的任务
        Runnable r1 = new MyRunnable01();
        Runnable r2 = new MyRunnable02();
        //5.创建具体的线程实例,接载具体线程要实现的任务
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
        t1.start();
        t2.start();
    }
}
/*
 * 实现Runnable接口的缺点: 结构稍微复杂一点
 * 优点:
 * 1.避免继承Thread类单继承的局限性,类是单继承多实现
 * 2.降低了线程对象和线程任务的耦合性
 */
//1.创建一个类,实现Runnable接口
class MyRunnable01 implements Runnable{
    //2.实现Runnable接口的run方法
    @Override
    public void run() {
        //3.写线程要实现的任务
        for (int i=0;i<1000;i++){
            System.out.println("第"+i+"次说:hello!姐~");
        }
    }
}
class MyRunnable02 implements Runnable{
    @Override
    public void run() {
        for(int i=0;i<1000;i++){
            System.out.println("第"+i+"次说:来了~老弟~");
        }
    }
}

从上面的运行结果可以看出,main方法(主线程)和run方法(子线程)中的两个for循环中的输出语句交替执行了,说明实现Runnable接口同样也实现了多线程。

总结

1. 多线程的意义是什么?

答:单线程程序执行时都只有一条顺序执行流,如果程序执行某行代码时遇到了阻塞(比如:抛异常),那么程序的运行将会停滞在这一行,其他代码将会无法执行!所以可以通过开启多个线程,让某些代码的执行可以实现并行的情况。

2. 多线程的创建方式?如何使用?

答:在Java中要想实现多线程操作有两种方式:① 实现类继承Thread类,然后通过重写run方法实现该线程的任务逻辑,最后通过start方法调用开启;

② 实现Runnable接口,然后通过重写run方法实现该线程的任务逻辑,最后通过start方法调用开启。

上篇文章:入门Java编程的知识点—>异常(day14)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/Z0412_J0103/article/details/141552392下篇文章:入门Java编程的知识点—>线程安全(day16)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/Z0412_J0103/article/details/141553816

  • 26
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值