首页 > 编程语言 >Java学习基础笔记——多线程基础部分

Java学习基础笔记——多线程基础部分

时间:2024-06-20 20:30:13浏览次数:27  
标签:同步 Java Thread synchronized 对象 基础 线程 多线程 方法

第十三章 多线程基础

13.1 线程介绍

13.1.1 线程相关概念

13.2 线程创建

13.2.1 创建线程的两种方式

13.2.2 继承Thread vs 实现 Runnable 的区别

13.2.3 线程终止

13.3 线程方法

13.3.1 常用方法第一组

13.3.2 常用方法第二组

13.3.3 用户线程和守护线程

13.4 Synchronized

13.4.1 线程同步机制

13.4.2 同步具体方法

13.5 互斥锁

13.5.1 基本介绍

13.5.2 注意事项和细节

13.6 死锁

13.6.1 基本介绍

13.7 释放锁

13.7.1 下面操作会释放锁

13.7.2 下面操作不会释放锁

第十三章 多线程基础

13.1 线程介绍

13.1.1 线程相关概念

  • 程序 -> 为完成特定任务、用某种语言编写的一组指令的集合。

  • 进程

    1. 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存空间。当我们使用迅雷,又启动了一个进程,操作系统将为迅雷分配新的内存空间

    2. 进程是程序的一次执行过程,或是正在运行的一个程序。是动态过程:有它自身的产生、存在和消亡的过程

  • 线程

    1. 线程由进程创建的,是进程的一个实体

    2. 一个进程可以拥有多个线程

  • 其他相关概念

    1. 单线程:同一个时刻,只允许执行一个线程

    2. 多线程:同一个时刻,可以执行多个线程,比如:一个qq进程,可以同时打开多个聊天窗口,一个迅雷进程,可以同时下载多个文件

    3. 并发:同一个时刻,多个任务交替执行,造成一种"貌似同时"的错觉,简单说,单核cpu实现的多任务就是并发

    4. 并行:同一个时刻,多个任务同时执行。多核cpu可以实现并行

13.2 线程创建

13.2.1 创建线程的两种方式

在java中, 线程使用方法常用的有两种

  • 继承Thread 类,重写 run方法

  • 实现Runnable接口,重写 run方法

  • 说明
    • java 是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然不可能了

    • java 设计者们提供了另一种方式创建编程,就是通过实现Runable接口来创建线程

13.2.2 继承Thread vs 实现 Runnable 的区别

  • 从 java 的设计来看,通过继承Thread 或者 实现 Runnable 接口来创建线程本质上没有区别,从jdk帮助文档我们可以看到Thread类本身就实现了Runnbale接口 start() -> start0()

  • 实现Runnable 接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制

13.2.3 线程终止

  • 基本说明

    1. 当线程完成任务后,会自动退出

    2. 还可以通过使用变量来控制run方法退出的方式停止线程

13.3 线程方法

13.3.1 常用方法第一组

  • setName //设置线程名称,使之与参数 name 相同

  • getName //返回该线程的名称

  • start //使该线程开始执行;Java 虚拟机底层调用该线程的 start0() 方法

  • run //调用线程对象 run 方法;

  • setPriority //更改线程的优先级

  • getPriority //获取线程的优先级

  • sleep //在指定的毫秒数内让当前正在执行的线程的休眠(暂时执行)

  • interrupt //中断线程

注意事项和细节

  • start 底层会创建新的线程,调用run, run 就是一个简单的方法调用,不会启动新线程

  • 线程优先级的范围【1, 5, 10】

  • interrupt,中断线程,但并没有真正的结束线程。所以一般用于中断正在休眠线程

  • sleep:线程的静态方法,使当前线程休眠

13.3.2 常用方法第二组

  • yield:线程的礼让。让出 cpu ,让其它线程执行,但礼让的时间不确定,所以也不一定礼让成功

  • join:线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程所有的任务

13.3.3 用户线程和守护线程

  • 用户线程:也叫工作线程,当线程的任务执行完或通知方式结束

  • 守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束    

  •  MyDaemonThread myDaemonThread = new MyDaemonThread();
            //如果我们希望当主线程结束后,子线程可以自动结束
            //只需将子线程设置为守护线程 即可
            //注意:要先设置守护线程,再启动
            myDaemonThread.setDaemon(true);
            myDaemonThread.start();
  • 常见的守护线程:垃圾回收机制

13.4 Synchronized

13.4.1 线程同步机制

  • 在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性

  • 也可以这样理解:线程同步,即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作

13.4.2 同步具体方法

//同步代码块

synchronized (对象) { // 得到对象的锁,才能操作同步代码

// 需要被同步代码;

}

synchronized 还可以放在方法声明中,表示整个方法为同步方法

public synchronized void m (String name) {

// 需要被同步的代码

}

//实现接口方式,使用synchronized 实现线程同步
class SellTicket03 implements Runnable {
​
    private int ticketNum = 100;//让多个线程共享 ticketNum
    private boolean loop = true;//控制run方法变量
​
    public synchronized void sell() { //同步方法,在同一时刻, 只能有一个线程来执行sell 方法
        if (ticketNum <= 0) {
            System.out.println("售票结束...");
            loop = false;
            return;
        }
​
        //休眠50毫秒, 模拟
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
​
        System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                + " 剩余票数=" + (--ticketNum));
    }
​
    @Override
    public void run() {
        while (loop) {
​
            sell();//sell方法是一个同步方法
        }
    }
}

13.5 互斥锁

13.5.1 基本介绍

  • 在Java 语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性

  • 每个对象都对应于一个可称为"互斥锁"的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象

  • 关键字synchronized 来与对象的互斥锁联系。当某个对象用 synchronized 修饰时,表明该对象在任一时刻只能由一个线程访问

  • 同步的局限性:导致程序的执行效率要降低

  • 同步方法(非静态的)的锁可以是this(默认),也可以是其他对象(要求是同一个对象)

  • 同步方法(静态的)的锁为当前类本身

    //同步方法(静态的)的锁为当前类本身

    //1. public synchronized static void m1() {} 锁是加在 SellTicket03.class
    //2. 如果在静态方法中,实现一个同步代码块
    /*
        synchronized (SellTicket03.class) {
                System.out.println("m2");
        }
     */
    public synchronized static void m1() {}
​
    public static void m2() {
        synchronized (SellTicket03.class) {
            System.out.println("m2");
        }
    }
​
    
    //1. public synchronized void sell() {} 就是一个同步方法
    //2. 这时锁在 this对象
    //3. 也可以在代码块上写 synchronized ,同步代码块 ,互斥锁还是在this对象
    public /*synchronized*/ void sell() { //同步方法,在同一时刻, 只能有一个线程来执行sell 方法
        synchronized (/*this*/ object) {
            if (ticketNum <= 0) {
                System.out.println("售票结束...");
                loop = false;
                return;
            }
        }
    }

13.5.2 注意事项和细节

  • 同步方法如果没有使用static 修饰,默认锁对象为this

  • 如果方法使用static 修饰,默认锁对象:当前类.class

  • 实现的落地步骤:

    1. 需要先分析上锁的代码

    2. 选择同步代码块或同步方法

    3. 要求多个线程的锁对象为同一个即可

13.6 死锁

13.6.1 基本介绍

  • 多个线程都占用了对方的锁资源,但不肯相让,导致了死锁,在编程时,一定要避免死锁的发生。

public class DeadLock_ {
    public static void main(String[] args) {
​
        //模拟死锁现象
        DeadLockDemo A = new DeadLockDemo(true);
        A.setName("A线程");
        DeadLockDemo B = new DeadLockDemo(false);
        B.setName("B线程");
        A.start();
        B.start();
    }
}
​
class DeadLockDemo extends Thread {
    static Object o1 = new Object();// 保证多线程,共享一个对象,这里使用static
    static Object o2 = new Object();
    boolean flag;
​
    public DeadLockDemo(boolean flag) {
        this.flag = flag;
    }
​
    @Override
    public void run() {
​
        //逻辑分析
        //1. 如果flag 为 T,线程A 就会先持有/得到 o1 对象锁,然后尝试去获取 o2 对象锁
        //2. 如果线程A 得不到 o2 对象锁,就会 Blocked
        //3. 如果flag 为 F,线程B 就会先持有/得到 o2 对象锁,然后尝试去获取 o1 对象锁
        //4. 如果线程B 得不到 o1 对象锁,就会 Blocked
        if (flag) {
            synchronized (o1) { //对象互斥锁,下面就是同步代码
                System.out.println(Thread.currentThread().getName() + " 进入1");
                synchronized (o2) { //这里获得 li 对象的监视权
                    System.out.println(Thread.currentThread().getName() + " 进入2");
                }
            }
        } else {
            synchronized (o2) { //对象互斥锁,下面就是同步代码
                System.out.println(Thread.currentThread().getName() + " 进入3");
                synchronized (o1) { //这里获得 li 对象的监视权
                    System.out.println(Thread.currentThread().getName() + " 进入4");
                }
            }
        }
    }
}

13.7 释放锁

13.7.1 下面操作会释放锁

  • 当前线程的同步方法、同步代码块执行结束

  • 当前线程在同步代码块、同步方法中遇到break、return

  • 当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束

  • 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁

13.7.2 下面操作不会释放锁

  • 线程执行同步代码块、同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行,不会释放锁

  • 线程执行同步代码块时,其他线程调用了该线程的suspend()方法,将该线程挂起,该线程不会释放锁

注意:应尽量避免使用suspend()和resume()来控制线程,方法不再推荐使用

标签:同步,Java,Thread,synchronized,对象,基础,线程,多线程,方法
From: https://blog.csdn.net/jiangnank/article/details/139773366

相关文章

  • Java学习基础笔记——反射机制
    第十五章反射15.1反射机制15.1.1 Java反射机制可以完成15.1.2 反射的优缺点15.2Class类15.2.1基本介绍15.2.2Class类常用方法15.2.3获取Class类对象6种方式15.3类加载15.3.1基本说明15.3.2类加载时机15.4反射获取类的结构信息15.5反射调用性能......
  • Python基础-类与对象
    1.面向对象的三大特性封装继承多态2.类与对象的理解与封装特性类是事物抽象的集合,对象是事物具象的个体。(类–>实例化–>对象)面向对象编程语言类:一个模板,(人类)—是一个抽象的,没有实体的对象:(eg:张三,李四)属性:(表示这类东西的特征,眼睛,嘴巴,鼻子)方法:(......
  • Java毕业设计 基于springboot vue音乐网站
    Java毕业设计基于springbootvue音乐网站SpringBoot音乐网站功能介绍首页图片轮播歌曲信息歌曲分类歌曲详情歌曲播放音乐下载评论注册登录个人中心更新信息用户后台:登录个人中心修改密码个人信息音乐下载管理员:登录个人中心修改密码个人信息用户管......
  • python基础语法
    目录字面量注释变量标识符运算符字符串扩展数据输入字面量字面量:在代码中,被写出来的固定的值,称之为字面量。python中常用的有6种值(数据)的类型:注释注释:在程序代码中对程序代码进行解释说明的文字。作用:注释不是程序,不能被执行,只是对程序代码进行解释说明,让别人可......
  • python 基础习题6--for循环和while循环
    1.用for循环打印1--10这10个数字,格式如下:运行结果如下: 12345678910 2.用 while循环打印1-10这个10个数字,请在横线处填空:counter=1whilecounter<= ________:print(counter)___________ 3.请问这段代码返回什么结果:(可以在环境中......
  • JAVA基础——接口(全网最详细教程)
    概述我们已经学完了抽象类,抽象类中可以用抽象方法,也可以有普通方法,构造方法,成员变量等。那么什么是接口呢?接口是更加彻底的抽象,JDK7之前,包括JDK7,接口中全部是抽象方法。接口同样是不能创建对象的。  把特有的方法(行为)写成接口,要用的时候调用接口就行了,除了狗和青蛙......
  • 2024年 Java 面试八股文(20w字)
    第一章-Java基础篇1、你是怎样理解OOP面向对象   难度系数:⭐面向对象是利于语言对现实事物进行抽象。面向对象具有以下特征:继承:继承是从已有类得到继承信息创建新类的过程封装:封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口多态性:多态性是指允......
  • Java面试八股文2024最新版
    一、java基础1、java有哪几种数据类型?基本数据类型:byte(1),char(2),short(2),int(4),long(8),double(8),float(4),boolean(1)引用数据类型:各种类和接口,枚举,数组2、 面向对象和面向过程的区别?面向对象和面向过程都是一种开发思想。面向过程就是根据解决问题所需要的步骤,具体化的一步一步的去实现......
  • Python入门_基础理论_全网详细版
    (根据黑马教程整理)第二章01-字面量0.6数据的类型1.掌握字面量的含义代码中,被写在代码中的固定值,称之为字面量2.常见的字面量类型整数、浮点数、字符串3.基于print语句完成各类字面量的输出print(10)print("今天是23年2月22日")第二章02-注释1.单行注释:#2.......
  • 微信小程序源码-基于Java后端的教学质量评价系统的计算机毕业设计(附源码+论文)
    大家好!我是程序员一帆,感谢您阅读本文,欢迎一键三连哦。......