JAVA多线程实战

一、线程概述

进程:是计算机中的程序关于某数据集合的一次运行活动,是操作系统进行资源分配和调度的基本单位
线程是操作系统能够进行运算调度的最小单位,一个线程就是进程中一个单一顺序的控制流,进程是线程的容器,一个进程至少有一个线程,一个进程可以有多个线程

OS中是以进程为单位分配资源,如虚拟存储控件、文件描述符。每个线程都有自己的线程栈

JVM启动时会自动创建一个主线程,该主线程负责执行main方法。主线程就是运行main方法的线程。

串行、并行、并发
在这里插入图片描述

二、线程的创建与启动

2.1 继承Thread类的形式创建线程

在Java中,创建一个线程就是创建一个Thread类(子类)的对象(实例)
Thread类有两个常用的构造方法:Thread()Thread(Runnable)对应的创建线程的两种方式
这两种方法没有本质的区别

public class Thread01 extends Thread{
    public static void main(String[] args) {
        System.out.println("JVM创建main线程执行main方法");

        Thread01 thread01 = new Thread01();
        //调用start()方法来启动线程,实质就是请求JVM运行相应的线程,这个线程具体什么时候运行由OS的线程调度器(Scheduler)决定
        //start()方法调用结束并不意味着子线程开始运行
        //新开启的进行会执行run方法
        //如果开启了多个线程,start()调用的顺序并不一定就是线程的启动顺序!
        //多线程运行结果和代码调用顺序无关
        thread01.start();

        System.out.println("main线程其他的代码...");
    }

    //run()方法的代码就是子线程要执行的任务
    //run()方法执行完线程就执行完了
    @Override
    public void run() {
        System.out.println("这是子线程打印的东西");
    }
}

在这里插入图片描述

2.2 多线程运行结果是随机的

public class Thread02 extends Thread{

    public static void main(String[] args) {
        Thread02 thread02 = new Thread02();
        thread02.start();


        for(int i = 0; i < 10; i++){
            System.out.println("main thread: " + i);
            try {
                // Math.random() -> [0,1]的小数
                int time = (int) (Math.random()*1000);
                Thread.sleep(time);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }

    @Override
    public void run() {
        for(int i = 0; i < 10; i++){
            System.out.println("sub thread: " + i);
            try {
                // Math.random() -> [0,1]的小数
                int time = (int) (Math.random()*1000);
                Thread.sleep(time);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

在这里插入图片描述

2.3 实现Runnable接口创建线程

把线程的具体实现交给Thread实例,本类只需实现Runnable接口,写出具体实现

/**
 * 当线程已经有父类了,就不能用继承Thread类创建线程
 * 可以使用实现Runnable接口的形式
 * 1)定义类实现Runnable接口
 */

public class MyRunnable implements Runnable{

    // 2)重写Runnable接口中的抽象方法run()
    // run()方法就是子线程要执行的代码
    @Override
    public void run() {
        for(int i = 0; i < 100; i++){
            System.out.println("sub thread -> " + i);
        }
    }

    public static void main(String[] args) {
        // 3)创建Runnable接口的实现类对象
        MyRunnable runnable = new MyRunnable();
        // 4)创建线程对象
        Thread t = new Thread(runnable);
        // 5) 启动线程
        t.start();


        for(int i = 0; i < 100; i++)
            System.out.println("main thread -> " + i);
    }
}

接口引用指向实现类的对象
接口引用调用实现类对象实现该接口的方法run()方法

本质是内存指向,对象空间

耦合度低

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

为什么要用接口引用指向实现类的对象?

这种写法其实Java多态的表现形式(一个接口类型的引用变量来引用实现接口的类的实例,当这个引用调用方法时,它会根据实际引用的类的实例来判断具体调用哪个方法)

多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)

为什么一般都使用 接口引用指向子类对象 ,而不用 实现类本身 引用呢?

问题就在于接口可以有多个实现类,如果现在你使用这个实现类接收,也许哪一天你需要换成其它的实现类呢?

这时你只要将new的实现类对象换成你想要的就行了, 其它地方的代码根本不需要改动。

三、线程的常用方法

currentThread()方法

Thread.currentThread()方法可以获得当前线程
Java中的任何一段代码都是执行在某个线程当中的。执行当前代码的线程就是当前线程
同一段代码可能被不同的线程执行,因此当前线程是相对的,Thread.currentThread()方法的返回值是在实际运行时候的线程对象

public class SubThread1 extends Thread{

    public SubThread1(){
        System.out.println("SubThread1构造方法 -> " + Thread.currentThread().getName());
    }

    //由Thread类中的方法调用执行
    @Override
    public void run() {
        // currentThread() native关键字修饰,调用C语言接口
        System.out.println("run方法 -> " + Thread.currentThread().getName());
    }



    public static void main(String[] args) {

        System.out.println("main -> " + Thread.currentThread().getName());

        SubThread1 subThread1 = new SubThread1();
        subThread1.start();
    }
}

在这里插入图片描述
一个复杂案例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值