首页 > 编程语言 >Java基础-学习笔记16

Java基础-学习笔记16

时间:2024-09-03 17:05:59浏览次数:16  
标签:同步 run Thread 16 笔记 线程 Java 执行 方法

16 线程(基础)

1. 相关概念

进程: 进程是程序的一次执行过程,或是正在运行的一个程序。是多态过程,有它自身的产生、存在和消亡的过程。(比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存看见。当我们使用迅雷,又启动了一个进程,操作系统将为迅雷分配新的内存空间。进程一旦中断,空间将会被释放。)

线程:线程由进程创建的,是进程的一个实体。一个进程可以拥有多个线程。(比如一个QQ进程,可以同时打开多个聊天窗口,一个迅雷进程,可以同时下载多个文件。)

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

多线程:同一个时刻,可以执行多个线程。

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

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

2. 线程基本使用

2.1 创建线程的两种方式

  • 2.1.1 继承 Thread 类,重写 run 方法
 public static void main(String[] args) throws InterruptedException
    {
        // 创建 Cat 对象,Cat 已继承 Thread,实现 run 方法。可以当作线程使用
        Cat cat = new Cat();
        cat.start(); // 启动线程,最终会直接执行 Cat 的 run 方法
        for (int i = 0; i < 10; i++) {
            System.out.println("主线程 i = "+ i);
        }
        Thread.sleep(1000); // 让主线程也间断休眠
    }
// 运行程序时,开启一个进程
// 执行 main 方法,此时进程会开启一个主线程(main 线程)
// 执行 Cat.start(),此时 main 线程会再开一个 子线程,Thread-0
// 主线程,不会阻塞,会继续执行fori。主线程和子线程在交替执行...
// 可以在终端输入jconsole监控线程执行情况。

Q:为什么是 start() 方法,不直接调 run()?

因为run方法是一个普通的方法,如果直接调,会作为一个普通方法串行来执行,并未真正启动一个线程。
此时,当run方法执行完毕,才会继续执行后面的语句。

源码分析

start() 方法里,调用 start0() 方法。
start0() 是本地方法,由 JVM 调用的。具体如何执行,取决于 CPU,也与操作系统、内存资源、IO资源等有关。
真正实现多线程的效果,是 start0(),而不是 run()。可以理解为,在 start0() 里面,用多线程的机制来调用 run 方法。

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

Java 是单继承的,在某些情况下一个类可能以及继承了某个父类,这时再用继承 Thread 类方法来创建线程显然不可能了。

此时可通过另外一个方式创建线程,就是通过实现 Runnable 接口来创建线程。

public static void main(String[] args) throws InterruptedException
{
     Dog dog = new Dog();// Dog 实现了 Runnable 接口,并重写了 run 方法。
     // dog.start(); // 这里无法调用start编译报错。更不能改用run原因同上。
     // 应当 创建一个 Thread 对象,把 dog 带进去。这里底层使用了设计模式 [代理模式]。
     Thread t1 = new Thread(dog);
     t1.start();
}
  • 2.1.3 两种方式的区别
  1. 从 Java 的设计来看,通过继承 Thread 或者实现 Runnable 接口来创建线程本质上没有区别,因为二者在底层都是通过调用 start0() 来实现的。

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

2.2 多线程执行

public static void main(String[] args) throws InterruptedException
{
    Cat cat = new Cat();
    cat.start();  // 启动第一个子线程
    Dog dog = new Dog();
    Thread t1 = new Thread(dog); 
    t1.start();  // 启动第二个子线程

    for (int i = 0; i < 30; i++)  // 主线程
    {
       System.out.println("main~~~~");
    }
}
class Dog implements Runnable
{
    @Override
    public void run() {
        int t = 0;
        while (t < 50)
        {
            System.out.println("wo~~~~");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

class Cat extends Thread
{
    @Override
    public void run()
    {
        int time = 0;
        while (time < 20)
        {
            System.out.println("miao~~~~");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            time += 1;
        }
    }
}

3. 线程终止

  • 基本说明:
  1. 当线程完成任务后,会自动退出。

  2. 还可以通过使用变量来控制 run 方法退出的方式停止线程,即通知方式
    比如,子线程的run方法里是一个循环方法,可在子线程里设置loop变量控制循环,并设置setLoop方法控制loop的值。那么,在main线程里,只需要通过调用setLoop方法即可控制子线程退出run方法。

  • 线程常用方法


  • 注意事项和细节

  • 线程状态

4. 线程的同步

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

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

  • 具体方法:
  1. 同步代码块
synchronized(对象) // 得到对象的锁,才能操作同步代码块
{
   // 需要被同步的代码 
}
  1. synchronized 还可以放在方法声明中,表示整个方法为同步方法
public synchronized void m()
{
   // 需要被同步的代码
}

5. 互斥锁

  • 基本介绍:
  1. Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。

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

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

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

  5. 同步方法(非静态的)的锁,其实是加在当前对象的。也可以是其它对象(要求是同一个对象,否则锁不上)

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

6. 线程的死锁

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

  • 释放锁:
  1. 当前线程的同步方法、同步代码块执行结束
  2. 当前线程在同步代码块、同步方法中遇到 break、return
  3. 当前线程在同步代码块、同步方法中出现了未处理的 error 或 exception,导致异常结束
  4. 当前线程在同步代码块、同步方法中执行了线程对象的 wait() 方法,当前线程暂停,并释放锁
  • 下面操作不会释放锁:
  1. 线程执行同步代码块或同步方法时,程序调用 Thread.sleep()、Thread.yield() 方法暂停当前线程的执行,不会释放锁
  2. 线程执行同步代码块时,其它线程调用了该线程的 suspend() 方法将该线程挂起,该线程不会释放锁。(最好避免使用)

标签:同步,run,Thread,16,笔记,线程,Java,执行,方法
From: https://www.cnblogs.com/97gogo/p/18387108

相关文章

  • Java数据库连接池的优化与配置
    Java数据库连接池的优化与配置大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!数据库连接池是现代Java应用中不可或缺的一部分,它允许多个用户共享一个固定数量的数据库连接,显著提高了应用程序的性能和可扩展性。本文将探讨如何优化和配置Java数据库连......
  • java+springboot权限的设计(用户、角色、权限)和前端如何渲染用户所对应的权限菜单
    记得当时在学校的时候,觉得这个实现起来真的超级困难,想想就头大,毫无头绪,即便那时候去查资料看了很多大佬写的文章,看的时候感觉恍然大悟,直拍大腿,但是当我想要动手自己去做的时候,又不知道从哪开始切入,于是一直没有动手去做,直到最近在实习的时候,给了我这个任务,当我带着恐惧去自......
  • javascript变量
    定义变量var声明变量的关键字vara;vara=10;varb=20.8;varc="demo";定义时不区分数据类型,但是使用时存在类型的区分变量类型:①基本类型:(零零散散不可拆分)数字类型1010.6字符串"aa"'aaa'布尔类型真/假true/falseundefined类型即声明变量但不进行赋......
  • 1001-基于51单片机LCD液晶显示器的8路抢答器(8路,串口,LCD1602)原理图 仿真 源代码
    1001-基于51单片机LCD液晶显示器的8路抢答器(8路,串口,LCD1602)原理图仿真源代码功能描述:8路抢答器1、提前抢答视为违规抢答,蜂鸣器提示2、A机为选手按钮控制,B机为主持人控制。双机通过串口通信3、可设置抢答时间:10s,20s,30s,40s4、LCD显示抢答过程有哪些资料:1、仿真工......
  • Java基础 韩顺平老师的 泛型 的部分笔记
    553,泛型引入packagecom.hspedu.list_;importjava.util.*;importjava.util.concurrent.CompletionService;@SuppressWarnings({"all"})publicclassMap_{publicstaticvoidmain(String[]args){//使用传统的方法来解决ArrayListarrayLis......
  • Java微服务架构设计:构建可扩展的服务
    Java微服务架构设计:构建可扩展的服务大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!微服务架构是一种将应用程序作为一套小服务开发的方法,每个服务运行在其独立的进程中,并通过轻量级的通信机制(通常是HTTPRESTfulAPI)进行交互。在Java中,构建微服务通......
  • Java中的依赖注入:Spring框架核心概念解析
    Java中的依赖注入:Spring框架核心概念解析大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在Java企业级应用开发中,Spring框架已成为事实上的标准。Spring的核心之一是依赖注入(DependencyInjection,DI),它是一种实现控制反转(InversionofControl,IoC)......
  • 代码大模型Wavecoder学习笔记及代码实践
    目录学习笔记摘要(Abstract)介绍(Introduction)CodeSeaXDataset:四任务代码相关指令数据四任务信息增强指令生成1.原始代码收集(WaveCoder-main\WaveCoder-main\src\data\raw_code_collection)2.基于LLM的生成器-鉴别器框架实验设置结果代码生成任务评估:其他代码相关任......
  • idea java开发 如何引入 一个 第三方 文件夹SDK源码,是SDK源码 不是 jar包
    在IntelliJIDEA中引入第三方文件夹作为SDK源码,而不是以jar包的形式,可以通过以下步骤来实现:打开项目:启动IntelliJIDEA,并打开你的项目。打开项目结构设置:点击菜单栏中的File->ProjectStructure...或使用快捷键Ctrl+Alt+Shift+S打开项目结构设置窗口。添加......
  • Java服务端数据库连接:连接池的资源优化
    Java服务端数据库连接:连接池的资源优化大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在Java服务端开发中,数据库连接池是提高数据库操作效率的关键技术之一。然而,随着系统负载的增加,如何优化连接池的资源使用成为了一个重要的问题。本文将探讨如何通......