Java进阶【多线程】

本文详细探讨了Java多线程的概念,包括并行与并发的差异,进程和线程的解析,线程调度原理以及主线程的角色。进一步讲解了通过继承Thread类和实现Runnable接口创建线程的方式,并分析了线程安全问题,如卖票案例和死锁现象。最后,介绍了线程的状态和JDK5引入的Lock接口,作为同步机制的替代选项。
摘要由CSDN通过智能技术生成

day07【多线程】

今日内容介绍

进程概念
线程概念
线程的创建方式
线程名字设置获取
线程安全问题引发
同步代码块
同步方法
死锁

第一章 多线程的概念【重点】

1.1 并行和并发

并行: 同一时刻,多个程序同时执行
并发: 同一时间段,多个程序交替执行

在这里插入图片描述

1.2 进程和线程的介绍

进程: 正在执行的一个软件/程序
每个进程:占用独立的内存空间
线程: 进程中的一个子程序,进程中的一个执行路径/执行单元
每个线程也有独立的内存空间

在这里插入图片描述

1.3 线程调度的原理

1.分时调度:
	为每个线程分配相同的执行时间
2.抢占式调度:
	CPU优先执行优先级别高的线程,多个相同优先级的线程,CPU就随机选择一个执行

1.4 主线程

一个可执行程序中
    至少有一个线程,用于执行main方法中的代码,称为主线程/main线程

在这里插入图片描述

第二章 线程的创建-继承方式

2.1 创建线程的第一种方式

java.lang.Thread: 代表线程类
	线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。

    创建线程的第一种方式: 继承Thread1.定义类继承Thread2.Thread类的子类覆盖重写run方法,作用是指定线程要执行的任务
        3.创建Thread类的子类对象
        4.Thread类的子类对象调用start方法,开启线程

    注意:
        1.开启线程必须调用start方法,不能直接调用run方法
            如果调用run方法,那么就是普通的方法调用,没有多线程的执行效果
            API中start方法说明: 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

        2.调用start方法,目的是以多线程的方式执行线程对象中的run方法
            当调用start方法时,start方法瞬间结束,
			但是线程对象中的run方法会继续执行(以多线程的方式执行)

        3.多线程程序运行结果具有随机性
/*
    1.定义类继承Thread类
    2.Thread类的子类覆盖重写run方法,作用是指定线程要执行的任务
 */
public class SubThread01 extends Thread {
   
    @Override
    public void run() {
   
        for (int i = 1; i <= 100; i++) {
   
            System.out.println("SubThread01...."+i);
        }
    }
}
//测试类
public class Demo02Thread {
   
    public static void main(String[] args) {
   

        //3.创建Thread类的子类对象
        SubThread01 st01 = new SubThread01();

        //4.Thread类的子类对象调用start方法,开启线程
        //st01.run();//如果调用run方法,那么就是普通的方法调用,没有多线程的执行效果

        st01.start();

        for (int i = 1; i <= 100; i++) {
   
            System.out.println("main~~~~~~~~~~~~~"+i);
        }

       /* Thread t = new Thread();
        t.start();*/
    }
}

在这里插入图片描述

2.2 多线程程序运行过程

在这里插入图片描述

2.3 继承Thread类开启线程源码分析

思考:
	既然Thread是线程类,为什么非得创建Thread的子类对象,并开启线程呢?

	Thread t = new Thread();
	t.start();

	直接创建Thread对象并开启线程,代码肯定没有问题,但是没有运行结果
	原因: 
		Thread类中的run方法指定的线程任务,不是我们想要的(理解: 什么代码都不行),
    	所以要继承Thread,重写run方法,指定我们自己的线程任务

 继承Thread类开启线程源码分析
     Thread类中成员变量:
     private Runnable target;//接口类型,必然传递实现类对象

     目前使用Thread类的空参构造创建对象:
     public Thread() {
   
         //第二个参数: null
         init(null, null, "Thread-" + nextThreadNum(), 0);
     }

     init方法:第二个参数Runnable接口类型
     //调用init时,第二个参数传递的是null
     //方法调用完毕以后: target == null
     private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
   
         init(g, target, name, stackSize, null, true);
     }


     线程对象调用start方法(Thread类内部定义的),开启线程
     	start方法,内部调用start0方法
     	start0方法,native修饰的本地方法
         	private native void start0()
    			该方法内部会调用系统资源,开启线程,调用Thread的run方法

    Thread类run方法源码
    public void run() {
   
		//因为空参构造创建Thread对象时,target是null target != null false
		if (target != null) {
   
			target.run();
		}
	}


总结:
	空参构造创建Thread对象,Thread类内部成员变量Runnable接口初始值null
	调用start方法开启线程,会调用run方法,内部判断Runnable是否为null,如果Runnable不是null,
	调用Runnable接口实现类对象的run方法

    如果创建的是Thread子类对象,覆盖重写了Thread类中的run方法
	Thread子类对象调用start方法开启线程,内部调用Thread子类覆盖重写后的run方法

在这里插入图片描述

2.4 多线程的内存解释

1.线程对象调用start方法,start方法通知JVM为当前线程对象开辟新的方法执行栈空间,
	执行当前线程对象的run方法
2.每个线程的run方法执行栈空间属于线程私有
3.某一个线程运行中出现异常,不会影响其它线程的执行
//Thread类的子类
public class SubThread02 extends Thread {
   
    @Override
    public void run() {
   

        for (int i = 1; i <= 100; i++) {
   
            //获取线程名称
            String threadName = super.getName();
            System.out.println(threadName+"....."+i);
            if(threadName.equals("Thread-0")&&(i==50)) {
   
                throw new RuntimeException("我要挂掉了,拜拜兄弟们..");
            }
        }
    }
}
//测试类
public class Demo02Thread {
   
    public static void main(String[] args) {
   
        //创建2个线程对象
        SubThread02 st01 = new SubThread02();
        SubThread02 st02 = new SubThread02();
        SubThread02 st03 = new SubThread02();

        //调用start方法开启线程
        st01.start();
        st02.start();
        st03.start();
        //throw new RuntimeException();
    }
}

在这里插入图片描述

2.5 获取线程名称

获取线程名称:
	1.Thread类的成员方法
     	public String getName(): 返回该线程的名称。
     	public void setName(String name): 设置该线程的名称。
     	public Thread(String name): 通过构造方法指定线程名称

	2.如何获取main线程的名称呢?
    	Thread类的静态方法            更灵活,建议使用
    	public static Thread currentThread(): 返回对当前正在执行的线程对象。
    		此方法currentThread在哪个线程中执行,获取到的就是那个线程对象
//Thread的子类
public class SubThread03 extends Thread {
   
    public SubThread03(String name) {
   
        super(name);
    }
    @Override
    public void run() {
   
        //获取线程名称
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值