Java核心API-多线程

news2024/11/17 14:26:02

多线程


文章目录

  • 多线程
  • 前言
  • 一、多线程
    • 1、多线程的概念
    • 2、多线程的好处
  • 二、主线程
    • 1、Thread类
    • 2、主线程
  • 三、线程的创建和启动
    • 1、创建线程的两种方式
    • 2、使用线程的步骤
  • 四、继承Thread类创建线程
  • 五、实现Runnable接口创建线程
  • 六、比较两种创建线程的方式
    • 1、继承Thread类
    • 2、实现Runnable接口
  • 七、线程的状态
  • 八、线程的调度
  • 九、线程优先级
  • 十、线程休眠
  • 十一、线程的强制执行
  • 十二、线程的礼让
  • 十三、多线程共享数据引发的问题
  • 十四、同步方法解决多线程共享数据引发的问题
    • 1、同步方法
    • 2、同步代码块
  • 十五、线程安全的类型


前言

理解线程的概念,掌握线程的创建和启动,了解线程的状态,掌握线程调度的常用方法,掌握线程的同步,理解线程安全的类型


一、多线程

1、多线程的概念

1)如果一个进程中同时运行了多个线程,用来完成不同的工作,则称为“多线程”

2)多个线程交替占用CPU资源,而非真正的并行执行

2、多线程的好处

1)充分利用CPU的资源

2)简化编程模型

3)带来良好的用户体验

二、主线程

1、Thread类

Java提供了java.lang.Thread类支持多线程编程

2、主线程

main()方法即为主线程入口

产生其它子线程的线程

必须最后完成执行,因为它执行各种关闭动作

public class ThreadDemo01 {

    public static void main(String[] args) {

        // 获取当前运行的线程
        // static Thread currentThread()返回对当前正在执行的线程对象的引用
        Thread thread = Thread.currentThread();
        /*
        因为Thread类中重写了Object类中的toString()方法
        所以在这里直接输出对象thread的时候,调用的是重写后的toString()方法,输出的是当前线程thread的一些内容信息
         */
        System.out.println("thread : " + thread);

        // 获取当前运行线程的名称
        // String getName()返回该线程的名称
        String threadName = thread.getName();
        System.out.println("当前线程名称 :" + threadName);

        // 修改当前线程名称
        // void setName(String name)改变线程名称,使之与参数 name 相同
        thread.setName("发发发");
        System.out.println("修改之后线程名 :" + thread.getName());

        // 获取当前运行线程的优先级
        // int getPriority()返回线程优先级
        System.out.println("当前线程优先级 :" + thread.getPriority());

        // 获取线程的最大优先级、最小优先级、默认优先级
        System.out.println("线程最大优先级 :" + Thread.MAX_PRIORITY); // 10
        System.out.println("线程最小优先级 :" + Thread.MIN_PRIORITY); // 1
        System.out.println("线程默认优先级 :" + Thread.NORM_PRIORITY); // 5

        // 修改当前线程优先级
        // void setPriority(int newPriority)更改线程的优先级
        thread.setPriority(8);
        System.out.println("修改后线程优先级 :" + thread.getPriority()); // 8


    }
}
/*
thread : Thread[main,5,main]
当前线程名称 :main
修改之后线程名 :发发发
当前线程优先级 :5
线程最大优先级 :10
线程最小优先级 :1
线程默认优先级 :5
修改后线程优先级 :8
*/

三、线程的创建和启动

1、创建线程的两种方式

1)继承java.lang.Thread类

2)实现java.lang.Runnable接口

2、使用线程的步骤

1)定义线程

2)创建线程对象

3)启动线程

4)终止线程

四、继承Thread类创建线程

1)定义MyThread类继承Thread类

2)重写run()方法,编写线程执行体

3)创建线程对象,调用start()方法启动线程

多个线程交替执行,不是真正的“并行”

线程每次执行时长由分配的CPU时间片长度决定

public class MyThread extends Thread {

    @Override
    public void run() {

        // 循环输出1-20之间所有的整数
        for (int i = 1; i <= 20; i++) {
            System.out.println(Thread.currentThread().getName() + "正在运行:" + i + "次");
        }

    }

}

// ------ ------ ------

public class Test {

    public static void main(String[] args) {

        // 创建自定义线程类MyThread对象
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();

        // 修改线程名
        myThread1.setName("线程A");
        myThread2.setName("线程B");

        // 启动线程
        // 通过线程对象直接调用run()方法,是由main来执行
        // myThread1.run(); // main正在运行:1-20次

        // 通过线程调用start()方法来启动线程,是由子线程来执行
        myThread1.start();
        myThread2.start(); // 多线程交替占用CPU的过程

    }

}

直接调用run()方法和start()方法的区别

直接调用run()方法只有主线程一条执行路径

调用start()方法多条执行路径,主线程和子线程并行交替执行

五、实现Runnable接口创建线程

1)定义MyRunnable类实现Runnable接口

2)实现run()方法,编写线程执行体

3)创建线程对象,调用start()方法启动线程

public class MyRunnable implements Runnable {

    public void run() {

        // 循环输出1-20之间所有的整数
        for (int i = 1; i <= 20 ; i++) {
            System.out.println(Thread.currentThread().getName() + "正在运行:" + i + "次");
        }

    }

}


package javaapidemo0221.demo03;

public class Test {

    public static void main(String[] args) {

        MyRunnable myRunnable = new MyRunnable();
        // 启动线程
        // myRunnable.run(); // main正在运行:1-20次
        // myRunnable.start(); // 报错
        /*
        myRunnable类中没有start()方法
        它的父类Object类中也没有start()方法,它实现的接口中也没有start()方法,因为start()方法是Thread类中
         */
        // Thread(Runnable target)分配新的 Thread 对象
        // Thread(Runnable target, String name)分配新的 Thread 对象
        // Thread thread1 = new Thread(myRunnable);
        // Thread thread2 = new Thread(myRunnable);
        Thread thread1 = new Thread(myRunnable, "线程A"); // 同时修改线程名称
        Thread thread2 = new Thread(myRunnable, "线程B");

        // 设置优先级,优先级高的线程比优先级低的线程获取CPU资源的概率更高一些
        // thread1.setPriority(1);
        // thread2.setPriority(10);

        thread1.start();
        thread2.start();

    }
}

六、比较两种创建线程的方式

1、继承Thread类

编写简单,可直接操作线程

适用于单继承

2、实现Runnable接口

避免单继承局限性

便于共享资源

七、线程的状态

1、创建状态

2、就绪状态

3、运行状态

4、阻塞状态

5、死亡状态

/*
新建(NEW):线程对象被创建后,尚未调用start()方法时的状态。
运行(RUNNABLE):线程对象调用start()方法后进入的状态,表示线程在逻辑上是可执行的,可能正在CPU上运行,也可能处于就绪状态等待调度。
阻塞(BLOCKED):线程阻塞于监视器锁,通常是等待获取一个对象的同步锁。
等待(WAITING):线程需要等待其他线程执行特定动作(如通知)才能继续执行的状态。
超时等待(TIMED_WAITING):与WAITING类似,但可以在指定时间后自动返回。
终止(TERMINATED):线程执行完毕或因异常而终止的状态。
*/

八、线程的调度

线程调度指按照特定机制为多个线程分配CPU的使用权

在这里插入图片描述

九、线程优先级

1)线程优先级由1-10表示,1最低,默认优先级为5

2)优先级高的线程获得CPU资源的概率较大

public class MyRunnable implements Runnable {

    @Override
    public void run() {

        for (int i = 1; i <= 20; i++) {
            System.out.println(Thread.currentThread().getName() + "正在运行:" + i + "次");
        }

    }

}


package javaapidemo0221.demo04;

public class Test {

    public static void main(String[] args) {

        // 创建MyRunnable类对象
        MyRunnable myRunnable = new MyRunnable();

        Thread thread1 = new Thread(myRunnable, "线程A");
        Thread thread2 = new Thread(myRunnable, "线程B");

        // 获取两个线程对象的优先级
        System.out.println("thread1线程优先级:" + thread1.getPriority()); // thread1线程优先级:5
        System.out.println("thread2线程优先级:" + thread2.getPriority()); // thread2线程优先级:5

        // 设置两个线程的优先级
        // 优先级只能反映线程获取CPU资源概率问题,优先级高的线程比优先级低的线程获取CPU资源的概率大,不能说优先级高的线程一定一优先级低的线程先获取CPU资源
        thread1.setPriority(Thread.MIN_PRIORITY);
        thread2.setPriority(Thread.MAX_PRIORITY);

        // 启动线程
        thread1.start();
        thread2.start();

    }
}

十、线程休眠

1)让线程暂时睡眠指定时长,线程进入阻塞状态

2)睡眠时间过后线程会再进入可运行状态

public static void sleep(long millis)// millis为休眠时长,以毫秒为单位
		// 调用sleep()方法需处理InterruptedException异常
		
		
package javaapidemo0221.demo05;

public class ThreadSleepDemo01 {

    public static void main(String[] args) throws InterruptedException {

        System.out.println("线程开始执行");

        // 线程休眠5秒钟
        Thread.sleep(5000);

        System.out.println("线程结束执行"); // 执行程序等待5s后输出线程结束执行

    }
}

public class MyThread extends Thread {

    @Override
    public void run() {
        for (int i = 100; i <= 5000; i++) {
            // public static Thread currentThread()返回对当前正在执行的线程对象的引用
            System.out.println(Thread.currentThread().getName() + "正在运行:" + i);
        }
    }
}


package javaapidemo0221.demo06;

public class Wait {

    // 定义一个静态方法实现线程休眠指定的秒数
    public static void waitBySecond(int second) {
        for (int i = 1; i <= second; i++) {
            System.out.println("正在休眠..." + i + "秒");
            // 处理异常
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

}


package javaapidemo0221.demo06;

public class MyRunnable implements Runnable {

    @Override
    public void run() {

        for (int i = 1; i <= 50; i++) {
            System.out.println(Thread.currentThread().getName() + "正在运行:" + i + "次");
            if (i == 25) {
                Wait.waitBySecond(5);
            }
        }
    }
}


package javaapidemo0221.demo06;

public class Test {

    public static void main(String[] args) {

        MyThread myThread = new MyThread();
        Thread thread = new Thread(new MyRunnable());

        // 启动两个线程
        myThread.start();
        thread.start();

    }
}

十一、线程的强制执行

使当前线程暂停执行,等待其它线程结束后再继续执行本线程

public final void join()
		public final void join(long mills)
		public final void join(long mills,int nanos)
		
		// millis:以毫秒为单位的等待时长
		// nanos:要等待的附加纳秒时长
		需处理InterruptedException异常
		
		
package javaapidemo0221.demo07;

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        for (int i = 1; i <= 20; i++) {
            System.out.println(Thread.currentThread().getName() + "正在运行:" + i + "次");
        }
    }
}


package javaapidemo0221.demo07;

public class Test {

    public static void main(String[] args) {

        Thread thread = new Thread(new MyRunnable());
        // thread.setPriority(10);
        thread.start();

        for (int i = 10; i <= 100; i += 10) {
            System.out.println(Thread.currentThread().getName() + "正在运行:" + i);
            if (i == 50) {
                try {
                    // 强制执行线程,会暂停当前正在运行的线程main,当强制执行的线程执行完了,暂停执行的当前线程会继续执行
                    thread.join();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }
}

十二、线程的礼让

暂停当前线程,允许其它具有相同优先级的线程获得运行机会

该线程处于就绪状态,不转为阻塞状态

public static void yield()
		// 只是提供一种可能,但是不保证一定会实现礼让
            
       
package javaapidemo0221.demo08;

public class MyRunnable implements Runnable{

    @Override
    public void run() {

        for (int i = 0; i <= 10 ; i++) {
            System.out.println(Thread.currentThread().getName() + "正在运行:" + i);

            if (i == 5) {
                System.out.println("线程礼让");
                // static void yield()暂停当前正在执行的线程对象,与其它线程一起抢占CPU资源。
                Thread.yield();
            }
        }

    }
}


package javaapidemo0221.demo08;

public class Test {

    public static void main(String[] args) {

        Thread thread1 = new Thread(new MyRunnable(), "线程A");
        Thread thread2 = new Thread(new MyRunnable(), "线程B");

        // 启动线程
        thread1.start();
        thread2.start();

    }
}

十三、多线程共享数据引发的问题

public class Site implements Runnable {

    // 定义两个属性来统计票的数目和买到第几张票
    // 票剩余的数量
    private int num = 10;
    // 购买到时是第几张票
    private int count = 0;

    @Override
    public void run() {

        while (true) {
            // 票卖完即结束循环
            if (num <= 0) {
                break;
            }

            num--;
            count++;

            // 模拟网络延迟
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            // 输出卖票信息,看是哪个线程(用户)购买了票
            System.out.println(Thread.currentThread().getName() + "购买了第" + count + "张票,剩余" + num + "张票");
        }

    }
}


package javaapidemo0221.demo09;

public class Test {

    public static void main(String[] args) {

        Site site = new Site();

        Thread thread1 = new Thread(site,"张三");
        Thread thread2 = new Thread(site,"李四");
        Thread thread3 = new Thread(site,"王五");

        // 启动线程
        thread1.start();
        thread2.start();
        thread3.start();

    }
}

/*
李四购买了第3张票,剩余7张票
王五购买了第3张票,剩余7张票
张三购买了第3张票,剩余7张票
李四购买了第6张票,剩余4张票
王五购买了第6张票,剩余4张票
张三购买了第6张票,剩余4张票
王五购买了第9张票,剩余1张票
张三购买了第9张票,剩余1张票
李四购买了第9张票,剩余1张票
王五购买了第10张票,剩余0张票
*/
/*
发现问题,没有从第一张票开始,存在多人抢到一张票的情况,有些票号没有被抢到
这是因为在某线程抢占到CPU资源时,因为网络延迟,CPU资源被其它线程抢占,无法输出语句
*/

十四、同步方法解决多线程共享数据引发的问题

1、同步方法

// 使用synchronized修饰的方法控制对类成员变量的访问
		访问修饰符 synchronized 返回类型 方法名(参数列表){……}
		// 或
		synchronized 访问修饰符 返回类型 方法名(参数列表){……}
		// synchronized就是为当前的线程声明一把锁


package javaapidemo0221.demo10;

public class Site implements Runnable {

    private int num = 10;
    private int count = 0;

    @Override
    public void run() {
        while (true) {
            if (!sale()) {
                break;
            }
        }
    }

    //定义一个同步方法,实现卖票
    public synchronized boolean sale() {
        if (num <= 0) {
            return false;
        }

        num--;
        count++;

        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println(Thread.currentThread().getName() + "购买了第" + count + "张票,剩余" + num + "张票");

        return true;
    }

}


package javaapidemo0221.demo10;

public class Test {

    public static void main(String[] args) {

        Site site = new Site();

        Thread thread1 = new Thread(site, "张三");
        Thread thread2 = new Thread(site, "李四");
        Thread thread3 = new Thread(site, "王五");

        //启动线程
        thread1.start();
        thread2.start();
        thread3.start();

    }
}
/*
张三购买了第1张票,剩余9张票
张三购买了第2张票,剩余8张票
张三购买了第3张票,剩余7张票
张三购买了第4张票,剩余6张票
张三购买了第5张票,剩余5张票
张三购买了第6张票,剩余4张票
张三购买了第7张票,剩余3张票
张三购买了第8张票,剩余2张票
张三购买了第9张票,剩余1张票
张三购买了第10张票,剩余0张票
*/

2、同步代码块

// 使用synchronized关键字修饰的代码块
		synchronized(syncObject){
    		// 需要同步的代码
		}
		// syncObject为需同步的对象,通常为this
		// 效果与同步方法相同
		public void run() {
    			while (true) {
        			synchronized (this) {   //同步代码块
        				// 省略修改数据的代码......
      	 				// 省略显示信息的代码......
		}}}

多个并发线程访问同一资源的同步代码块时

1)同一时刻只能有一个线程进入synchronized(this)同步代码块

2)当一个线程访问一个synchronized(this)同步代码块时,其他synchronized(this)同步代码块同样被锁定

3)当一个线程访问一个synchronized(this)同步代码块时,其他线程可以访问该资源的非synchronized(this)同步代码

public class Site implements Runnable {

    private int num = 10;
    private int count = 0;

    @Override
    public void run() {
        while (true) {

            synchronized (this) {
                //票卖完了就可以结束这个循序
                if (num <= 0) {
                    break;
                }

                num--;
                count++;

                //模拟网络延迟
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                //输出一下卖票信息,看是哪一个线程(用户)购买了票
                System.out.println(Thread.currentThread().getName() + "购买了第" + count + "张票,剩余" + num + "张票");
            }

        }
    }

}


package javaapidemo0221.demo11;

public class Test {

    public static void main(String[] args) {

        Site site = new Site();

        Thread thread1 = new Thread(site, "张三");
        Thread thread2 = new Thread(site, "李四");
        Thread thread3 = new Thread(site, "王五");

        //启动线程
        thread1.start();
        thread2.start();
        thread3.start();

    }
}

十五、线程安全的类型

常见类型比较

1)Hashtable && HashMap

Hashtable

继承关系:实现了Map接口,Hashtable继承Dictionary类

线程安全,效率较低

键和值都不允许为null

HashMap

继承关系:实现了Map接口,继承AbstractMap类

非线程安全,效率较高

键和值都允许为null

2)StringBuffer && StringBuilder

前者线程安全,后者非线程安全

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1479392.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python爬取网站视频资源

思路&#xff1a; 在界面找到视频对应的html元素位置&#xff0c;观察发现视频的url为https://www.pearvideo.com/video_视频的id&#xff0c;而这个id在html中的href中&#xff0c;所以第一步需要通过xpath捕获到所需要的id 在https://www.pearvideo.com/video_id的页面&…

C语言while 语句的基本格式是什么?

一、问题 C语⾔中有三种循环语句&#xff0c;while 语句是其中的⼀个&#xff0c;它的基本格式是怎样的呢&#xff1f; 二、解答 while 语句的⼀般形式为&#xff1a; while(表达式) 语句; 其中&#xff0c;表达式是循环条件&#xff0c;语句为循环体。 注意&#xff1a; …

测试环境搭建整套大数据系统(七:集群搭建kafka(2.13)+flink(1.13.6)+dinky(0.6)+iceberg)

一&#xff1a;搭建kafka。 1. 三台机器执行以下命令。 cd /opt wget wget https://dlcdn.apache.org/kafka/3.6.1/kafka_2.13-3.6.1.tgz tar zxvf kafka_2.13-3.6.1.tgz cd kafka_2.13-3.6.1/config vim server.properties修改以下俩内容 1.三台机器分别给予各自的broker_id…

奇点云:SAFe框架下,我们对平台软件工程生产线做了4项改造

导读&#xff1a; 客户规模扩大&#xff0c;如何保证大数据软件产品和服务质量始终如一&#xff1f;几乎所有成长中的软件厂商&#xff0c;尤其是需要通过私有化部署交付的厂商&#xff0c;都会面临这个问题。正如《人月神话》中多次表明的&#xff0c;单纯地增加人手、扩大团队…

npm使用国内淘宝镜像的方法整理

命令配置安装&#xff1a; 淘宝镜像&#xff1a; npm config set registry https://registry.npm.taobao.org/ 官方镜像&#xff1a; npm config set registry https://registry.npmjs.org 通过cnpm安装&#xff1a; npm install -g cnpm --registryhttps://registry.npm.…

Java-常用集合

Jva常用集合 一、Java 集合框架体系二、Collection接口和方法1. List接口List 接口主要实现类&#xff1a;ArrayListList 的实现类之二&#xff1a;LinkedListList 的实现类之三&#xff1a;Vector 2. Set接口Set 主要实现类&#xff1a;HashSetSet 实现类之二&#xff1a;Link…

SpringBoot 手写 Starter

spring-boot-starter 模块 1.介绍 SpringBoot中的starter是一种非常重要的机制&#xff0c;能够抛弃以前繁杂的配置&#xff0c;将其统一集成进starter&#xff0c;应用者只需要在maven中引入starter依赖&#xff0c;SpringBoot就能自动扫描到要加载的信息并启动相应的默认配…

WordPress分类目录ID怎么看?如何查找WordPress标签ID?

在WordPress网站中&#xff0c;我们需要判断某篇文章是否属于某个分类目录&#xff0c;或者是否拥有某个标签&#xff0c;那么就需要用到分类目录ID和标签ID&#xff0c;那么WordPress分类目录ID怎么看&#xff1f;如何查找WordPress标签ID&#xff1f;下面boke112百科就跟大家…

MySQL 自增列解析(Auto_increment)

MySQL数据库为列提供了一种自增属性&#xff0c;当列被定义为自增时。Insert语句对该列即使不提供值&#xff0c;MySQL也会自动为该列生成递增的唯一标识&#xff0c;因此这个特性广泛用于主键的自动生成。 一、自增列的用法 自增列具有自动生成序列值&#xff0c;整型&#…

Linux系统编程入门(下)

Linux系统编程 第一章 Linux系统编程入门&#xff08;下&#xff09;1.6 GDB 调试1.7 标准C库IO函数和Linux系统IO函数对比 第一章 Linux系统编程入门&#xff08;上&#xff09; 第一章 Linux系统编程入门&#xff08;下&#xff09; 1.6 GDB 调试 &#xff08;1&#xff0…

AOP(黑马学习笔记)

AOP基础 学习完spring的事务管理之后&#xff0c;接下来我们进入到AOP的学习。 AOP也是spring框架的第二大核心&#xff0c;我们先来学习AOP的基础。 在AOP基础这个阶段&#xff0c;我们首先介绍一下什么是AOP&#xff0c;再通过一个快速入门程序&#xff0c;让大家快速体验A…

JVM性能优化

运行时优化 方法内联 方法内联&#xff0c;是指 JVM在运行时将调用次数达到一定阈值的方法调用替换为方法体本身 &#xff0c;从而消除调用成本&#xff0c;并为接下来进一步的代码性能优化提供基础&#xff0c;是JVM的一个重要优化手段之一。 注&#xff1a; C的inline属于编…

构建一个基于Node.js的文件存储服务

随着现代web应用程序变得越来越复杂和功能强大&#xff0c;文件存储服务成为了许多应用的重要组成部分。在本篇博客中&#xff0c;我们将探讨如何构建一个基于Node.js的文件存储服务&#xff0c;让您可以轻松地上传、下载和管理文件。我们将利用Node.js的强大功能和模块来构建这…

【Javascript编程实操01】判断最大数、奇偶数、是否成年

目录 前言 1、求两个数的最大数 代码&#xff1a; 实现效果&#xff1a; 2、判断一个整数是偶数还是奇数 代码&#xff1a; 实现效果&#xff1a; 3、判断一个人的年龄是否满18岁 代码&#xff1a; 实现效果&#xff1a; 总结 前言 从今天开始正式进入了Web前端第二…

信安数学(验证定理6.3.2~6.3.3)

定理6.3.2 如果n是对于基b的强伪素数&#xff0c;则n是对于基b得到欧拉伪素数 nint(input("给定一奇合数n&#xff1a;")) bint(input("给定一个整数b&#xff1a;")) def solution(a,b):#若b>a&#xff0c;则交换两个数的值if(b>a):taabbtr b #初…

字符函数与字符串函数(上)

个人主页&#xff08;找往期文章包括但不限于本期文章中不懂的知识点&#xff09;&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 目录 strlen的使用与模拟实现 函数原型&#xff1a; strlen的使用 strlen的模拟使用 strcpy的使用与模拟实现 函数原型&#xff1a; strcpy的使…

【冲击蓝桥篇】动态规划(上):真题实战+思路解析

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《数据结构与算法&#xff1a;初学者入门指南》&#x1f4d8;&am…

普中51单片机学习(EEPROM)

EEPROM IIC串行总线的组成及工作原理 I2C总线的数据传送 数据位的有效性规定 I2C总线进行数据传送时&#xff0c;时钟信号为高电平期间&#xff0c;数据线上的数据必须保持稳定&#xff0c;只有在时钟线上的信号为低电平期间&#xff0c;数据线上的高电平或低电平状态才允许…

【Java 基础】Java 数组、方法极致精讲

《Java 零基础入门到精通》专栏持续更新中。通过本专栏你将学习到 Java 从入门到进阶再到实战的全套完整内容,所有内容均将集中于此专栏。无论是初学者还是有经验的开发人员,都可从本专栏获益。 订阅专栏后添加我微信或者进交流群,进群可找我领取 前端/Java/大数据/Python/低…

从0到1使用C++实现一个模拟器-1-【实现最简CPU】

文章目录 uint64_tstdstd::arrayCPU和CU类构造函数size_tstatic_caststd::ifstreamriscv64-unknown-elf-objcopy -O binary add-addi add-addi.binriscv64-unknown-elf-gcc -Wl,-Ttext0x0 -nostdlib -o add-addi add-addi.s-wlstd::hex std::setw() std::setfill()各自的用法he…