day24_多线程

news2024/10/6 8:36:51

今日内容

零、 复习昨日
一、作业
二、线程安全的集合
三、死锁
四、线程通信
五、生产者消费者
六、线程池

零、 复习昨日

见晨考

一、作业

售卖后车票

见代码

二、线程安全的类[了解]

StringBuffer是线程安全的,是因为每个方法都加上synchronized,即都是同步方法
StringBuilder没有加

image-20230303094122011

image-20230303094159112

ArrayList是线程不安全
Vector 是线程安全

image-20230303094527278

HashMap 是线程不安全
Hashtable 是线程安全

image-20230303095012216

比HashMap安全,比Hashtable快,即安全又快的集合ConcurrentHashMap[很重要]

三、死锁[了解]

死锁: 互相持有对方的锁还不释放

public class MyLock {
    // 左筷子锁
    static Object zuo = new Object();
    // 右筷子锁
    static Object you = new Object();

}
public class Girl extends Thread{

    @Override
    public void run() {
        synchronized (MyLock.zuo) {
            System.out.println("女朋友获得左筷子" );
            synchronized (MyLock.you) {
                System.out.println("女朋友获得右筷子-吃饭" );
            }
        }
    }
}
public class Boy extends Thread{

    @Override
    public void run() {
        synchronized (MyLock.you) {
            System.out.println("男朋友获得右筷子" );
            synchronized (MyLock.zuo) {
                System.out.println("男朋友获得右左筷子-吃饭" );
            }
        }
    }
}
public class TestDeadLock {
    public static void main(String[] args) {
        new Boy().start();
        new Girl().start();
    }
}

四、线程通信[熟悉]

4.1 介绍

线程通信,就是线程之间产生联系.

即通知,例如线程A执行到一定时候会停下,同时通知另外的线程B执行,
线程B执行到一定时候,也停下,通知线程A执行

以上操作需要Object类的方法

  • wait() 让当前线程等待
  • notify() 唤醒一个处于等待状态的线程
  • notifyAll() 唤醒所有处于等待状态的线程

4.2 两个个线程通信

需求: 昨天打印机方法,让print1()和print2()方法交替执行

package com.qf.notify;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 通信
 */
public class Printer {

    /**
     * 打印机执行的标志
     * 此标志如果是1,说明该打印机1执行,否则打印机1停下
     * 此标志如果是2,说明该打印机2执行,否则打印机2停下
     */
    private int flag = 1;

    public synchronized void print1() throws InterruptedException {
        if (flag != 1) { // 判断不是自己执行时
            // 线程停下不执行
            // 锁对象是谁,谁去wait方法
            this.wait();
        }
        System.out.print("1 " );
        System.out.print("2 " );
        System.out.print("3 " );
        System.out.print("4 " );
        System.out.print("\r\n" );

        // 改变标志
        flag = 2;
        // 通知其他处于等待状态的线程,起来干活
        // 锁对象是谁,谁去notify方法
        this.notify();
    }

    public synchronized void print2() throws InterruptedException {
        if ( flag != 2) {
            this.wait();
        }
        System.out.print("A " );
        System.out.print("B " );
        System.out.print("C " );
        System.out.print("D " );
        System.out.print("\r\n" );

        flag = 1;
        this.notify();
    }
}
public class TestNotify {
    public static void main(String[] args) {
        Printer printer = new Printer( );

        new Thread(){
            @Override
            public void run() {
                while(true){
                    try {
                        printer.print1();
                    } catch (InterruptedException e) {
                        e.printStackTrace( );
                    }
                }
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                while(true){
                    try {
                        printer.print2();
                    } catch (InterruptedException e) {
                        e.printStackTrace( );
                    }
                }
            }
        }.start();
    }
}

换用同步代码块实现

package com.qf.notify;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 通信
 */
public class Printer2 {
    Object obj = new Object();

    private int flag = 1;

    public void print1() throws InterruptedException {
        synchronized (obj) {
            if (flag != 1) { // 判断不是自己执行时
                // 线程停下不执行
                // 锁对象是谁,谁去wait方法
                obj.wait( );
            }
            System.out.print("1 ");
            System.out.print("2 ");
            System.out.print("3 ");
            System.out.print("4 ");
            System.out.print("\r\n");

            // 改变标志
            flag = 2;
            // 通知其他处于等待状态的线程,起来干活
            // 锁对象是谁,谁去notify方法
            obj.notify( );
        }
    }

    public void print2() throws InterruptedException {
        synchronized (obj) {
            if (flag != 2) {
                obj.wait( );
            }
            System.out.print("A ");
            System.out.print("B ");
            System.out.print("C ");
            System.out.print("D ");
            System.out.print("\r\n");

            flag = 1;
            obj.notify( );
        }
    }
}

总结

  • 通信的代码(wait和notify等)需要放在同步方法或者同步代码块里面
  • 通信的代码(wait和notify等)必须使用当前锁对象来调用

4.3 练习

创建A1 A2 两个线程,分别打印1-10,11-20,保证A1执行完再 执行A2线程,A2执行完再执行A1

A1 —> 1
A2 —>11
A1 —> 2
A2 —>12

package com.qf.notify;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class TestA1A2 {

    static int flag = 1;

    public static void main(String[] args) {
        Object o = new Object( );
        new Thread( ) {
            @Override
            public void run() {
                for (int i = 1; i < 11; i++) {
                    synchronized (o) {
                        if (flag != 1) {
                            try {
                                o.wait( );
                            } catch (InterruptedException e) {
                                e.printStackTrace( );
                            }
                        }
                        System.out.println("A1 -->" + i);
                        flag = 2;
                        o.notify( );
                    }
                }
            }
        }.start( );

        new Thread( ) {
            @Override
            public void run() {
                for (int i = 11; i < 21; i++) {
                    synchronized (o) {
                        if (flag != 2) {
                            try {
                                o.wait( );
                            } catch (InterruptedException e) {
                                e.printStackTrace( );
                            }
                        }
                        System.out.println("A2 -->" + i);
                        flag = 1;
                        o.notify( );
                    }
                }
            }
        }.start( );
    }
}

4.4 三个线程的通信

如果是notify

第一次
线程3抢到,判断标志是1,不是自己执行,线程3等待.此时1,2有线程都处于就绪状态


假如线程2抢到,判断标志是1,不是自己执行,线程2等待,此时1线程处于就绪状态


只能是线程1执行,执行完后,改标记为2,随机唤醒一条线程,假如是线程2,此时线程1,2处于活跃状态


第二次

假如线程1抢到,线程1执行后发现不是自己执行,线程1等待,此时只有2线程活跃,所以2线程执行,改标记为3,随机唤醒一条线程,假如是线程3,此时线程2,3处于活跃状态

假如线程2抢到,不是自己执行,线程2等待,此时只有3线程能执行,那么3线程执行,改变标记为1,唤醒的是线程2,此时线程2,3就绪,就算线程2,3抢到也会陷入等待状态,此时3个线程全部等待,没有可执行线程…

解决方案: 全部唤醒 ,使用方法notifyAll(),唤醒所有处于等待状态的线程

package com.qf.notify;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class Printer {

    int flag = 1;

    public synchronized void print1() throws Exception{
        while (flag != 1) {
            this.wait();// 哪里等待,被唤醒后继续执行,
            // 将此处的if改成while,目的是让线程唤醒后继续回头再判断一次
        }
        System.out.print("1 ");
        System.out.print("2 ");
        System.out.print("3 ");
        System.out.print("4 ");
        System.out.print("\r\n");

        flag = 2;
        //this.notify();// 随机唤醒处于等待状态的一条线程
        this.notifyAll();// 唤醒全部处于等待状态的线程

    }

    public synchronized void print2() throws Exception{
        while (flag != 2) {
            this.wait();
        }
        System.out.print("A ");
        System.out.print("B ");
        System.out.print("C ");
        System.out.print("D ");
        System.out.print("\r\n");

        flag = 3;
        this.notifyAll();

    }

    public synchronized void print3() throws Exception{
        while (flag != 3) {
            this.wait();
        }
        System.out.print("一 ");
        System.out.print("二 ");
        System.out.print("三 ");
        System.out.print("四 ");
        System.out.print("\r\n");

        flag = 1;
        this.notifyAll();
    }
}

4.5 总结

特殊的:

  • wait和notify方法需要在同步方法或者同步代码块内执行
  • wait会让当前线程进入等待状态,让出资源,其他线程可以执行
  • wait和notify()方法谁调用? 当前锁对象是谁,就是谁调用该方法

问 wait和sleep有什么区别?

答:

  • wait是Object类的方法,sleep是Thread类方法

  • wait和sleep都可以让当前线程进入阻塞状态

  • 但是wait阻塞当前线程,会让出系统资源,其他线程可执行;但是sleep阻塞当前线程,会持有锁不释放,其他线程无法执行

  • wait需要在同步方法或同步代码快中使用,但是sleep可以在同步或非同步都可以使用


问 为什么wait和notify方法要设计在Object类中?

答: 因为锁可以是任意对象,又因为wait和notify需要被 锁对象调用,那么锁对象是任意的,wait和notify方法也能被任意对象调用,所以就设计在Object类中,因为Object类是所有类的父类

五、生产者消费者

若干个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置⼀个能存储多个产品的缓冲区,生产者将生产的产品放入缓冲区中,消费者从缓 冲区中取走产品进行消费,显然生产者和消费者之间必须保持同步,即不允许消费者到⼀个空的缓冲区中取产品,也不允许生产者向⼀个满的缓冲区中放入产品。

商品类 Phone
商店类 Shop


商店类中要有生产线程,一个消费线程

package com.qf.pc;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 商品
 */
public class Phone {
    private String desc;

    public Phone(String desc) {
        this.desc = desc;
    }

    @Override
    public String toString() {
        return "Phone{" +
                "desc='" + desc + '\'' +
                '}';
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}
package com.qf.pc;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class Shop {

    private Phone phone;

    // 进货(生产)
    public synchronized void product(Phone phone) {
        if (this.phone != null) {// 如果商店还有手机,暂时等待消费先不生产
            try {
                //System.out.println("商店有手机,请来消费" );
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace( );
            }
        }

        // 如果商店没手机,就生产
        this.phone = phone;
        System.out.println("生产中...." );
        // 通知消费
        this.notify();
    }
    // 消费
    public synchronized void consumer() {
        if (this.phone == null) {// 商店没有手机,等待生产
            try {
                //System.out.println("商店没有手机,请赶紧生产...");
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace( );
            }
        }

        // 消费完,手机就没啦
        this.phone = null;
        System.out.println("消费中..." );
        // 通知生产
        this.notify();

    }

    public static void main(String[] args) {
        Shop shop = new Shop( );
        new Thread(){ // 一个线程生产
            @Override
            public void run() {
                for (int i = 1; i < 10; i++) {
                    shop.product(new Phone("XIAOMI"+i));
                }
            }
        }.start();

        new Thread(){ // 一个线程消费
            @Override
            public void run() {
                for (;;) {
                    shop.consumer();
                }
            }
        }.start();
    }
}

六、线程池

6.1 线程池概念

  • 如果有非常多的任务需要非常多的线程来完成,每个线程的工作时间不长,就需要创建很多线程,工作完又立即销毁[线程频繁创建和销毁线程]
  • 频繁创建和销毁线程非常消耗性能,那么线程池,就是可以创建一些线程,放在"池子"中,用的时候去池子取一个线程去使用,使用完再放回去,线程可以重用
  • 线程池,底层其实就是集合队列,里面存储线程对象,用的时候去抽即可,就不要频繁创建线程了

使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资
源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存(OOM Out Of Memory)或者“过度切换”的问题 --> 摘自阿里官方手册

6.2 线程池原理

image-20230301230326324

将任务(task)提交(submit/execute)给线程池(threadpool),由线程池分配线程,运行任务,任务结束后,线程重新放入线程池供后续线程使用

6.3 创建线程池的方式

使用线程池创建线程,执行任务

JDK提供了关于线程池的一些类和接口

  • Executor: 线程池的根接口,通过execute(Runnable task) 执行任务
  • ExecutorService: Executor的子接口,通过submit(Runnable task) 来提交任务,执行任务,并且可以获得返回值
  • ThreadPoolExecutor: ExecutorService的子实现类,通过submit(Runnable task) 来提交任务,执行任务
  • Executors: 执行器类(线程池工厂类),通过该类提供的静态方法来获得不同特点的线程池对象

6.4 不同特点的线程池

通过Executors调用以下静态方法获得不同特点的线程池对象

方法类型解释
newFixedThreadPool固定大小线程池池中包含固定数目的线程,空闲线程一直保留。只有核心线程,线程数量固定,任务队列为LinkedBlockingQueue
newCachedThreadPool动态大小的线程池,原则上无上限无核心线程,非核心线程数量无限,执行完闲置60s后回收,任务队列SynchronousQueue
newScheduledThreadPool可以执行定时任务的线程池用于调度执行的固定线程池,执行定时或周期性任务。和弦线程数量固定,非核心线程数量无线,执行完闲置10ms后回收,任务队列为DelayedWorkQueue
newSingleThreadExecutor单线程线程池只有一个线程的池,会顺序执行提交的任务,只有一个核心线程,无非核心线程,任务队列为LinkdBlockingQueue
newSingleThreadScheduledExecutor单线程定时任务线程池
newWorkStealingPool1.8提供新的方式创建线程池

以上线程池操作在阿里java开发手册中是不建议用的…

说明:Executors 返回的线程池对象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
-----------------------
OOM 内存溢出,即系统资源耗尽

线程池执行任务时,可以采用两种方法:

execute(): 没有返回值,无法判断任务是否执行成功

submit():会返回Future对象,通过该对象判断任务是否执行成功

package com.qf.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class TestThreadPool {
    public static void main(String[] args) {

        ExecutorService threadPool = Executors.newSingleThreadExecutor( );

        for (int i = 0; i < 10; i++) {
            threadPool.execute(new Runnable( ) {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"执行任务" );
                }
            });
        }

        threadPool.shutdown();

    }

    private static void show3() {
        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3);

        // execute这样没有定时执行
        // threadPool.execute(new Runnable( ) {
        //     @Override
        //     public void run() {
        //         System.out.println(Thread.currentThread().getName()+"执行任务" );
        //     }
        // });
        /**
         * schedule(Runnable r,long delay,TimeUnit 单位)
         */
        for (int i = 0; i < 3; i++) {
            threadPool.schedule(new Runnable( ) {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"执行任务" );
                }
            },3, TimeUnit.SECONDS);
        }

        threadPool.shutdown();
    }

    private static void show2() {
        // 创建缓冲线程池
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool( );
        for (int i = 0; i < 5000; i++) {
            cachedThreadPool.execute(new Runnable( ) {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"执行任务..." );
                }
            });
        }

        cachedThreadPool.shutdown();
    }

    /**
     * 固定大小线程池
     */
    private static void show1() {
        // 使用工具类来创建不同类型的线程池
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);


        // 执行任务
        // void execute()
        // Future submit()
        for (int i = 1; i < 41; i++) {
            fixedThreadPool.execute(new Runnable( ) {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"在执行..." );
                }
            });
        }

        // 线程池关闭
        fixedThreadPool.shutdown();
    }
}

6.5 ThreadPoolExecutor[重要]

  • ThreadPoolExecutor 很重要,有7个参数
参数名解释备注
int corePoolSize指定线程池的线程数量(核心线程数)不能小于0
int maximumPoolSize指定线程池可支持的最大线程数最大数量>=核心线程数
long keepAliveTime指定临时线程的最大存活时间不能小于0
TimeUnit unit指定存活时间的单位(秒,分,时,天)时间单位
BlockingQueue workQueue指定任务队列
ThreadFactory threadFactory指定哪个线程工厂创建线程
RejectedExecutionHandler handler指定线程忙,任务队列满的时候新任务来了怎么办?拒绝策略

这几个参数解释(某大型火锅店会例子)

  • 核心线程数5, 即店里面的固定员工5个
  • 最大线程数15,即突然顾客太多,5个人忙不过来,临时招聘10个人来干活
  • 最大存活时间,即顾客不多的时候,这些临时工可以待多长时间
  • 时间单位
  • 任务队列10,即集合, 固定员工加上临时工还处理不了顾客,在店门口放几10张凳子
  • 线程工厂, 如何创建出的线程? 即怎么找到的员工
  • 拒绝策略. 当固定员工,临时工,以及门口的凳子都坐满了,不让吃去别的地方

问: 什么是创建临时线程?
答: 新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建线程

问:什么时候开始拒绝任务?
答:核心线程和临时线程都在忙,任务队列也满了,新的任务过来就会拒绝

public static void main(String[] args) {
    ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(10);
    // new ThreadPoolExecutor(
    //        5,// 核心线程数
    //        15,// 最大线程数
    //        1, // 存活时间
    //        TimeUnit.MINUTES,
    //         queue,// 任务队列
    //         Executors.defaultThreadFactory(),// 默认的工厂
    //         new ThreadPoolExecutor.AbortPolicy());// 拒绝策略

    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
        5,// 核心线程数
        15,// 最大线程数
        1, // 存活时间
        TimeUnit.MINUTES,
        queue// 任务队列
    );

    for (int i = 0; i < 45; i++) {
        threadPoolExecutor.execute(new Runnable( ) {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"执行..." );
            }
        });
    }

    System.out.println(queue );
    System.out.println(queue.size() );
}

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

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

相关文章

【前端】前后端分离ruoyi-vue初步学习

1.了解vue基础知识。 Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org) 2.将ruoyi-vue项目拉下来&#xff0c;并成功运行。 开源项目网址&#xff1a;RuoYi 若依官方网站 |后台管理系统|权限管理系统|快速开发框架|企业管理系统|开源框架|微服务框架|前后端分离框架|…

《Netty》从零开始学netty源码(五十四)之PoolThreadLocalCache

PoolThreadLocalCache 前面讲到PoolThreadCache&#xff0c;它为线程提供内存缓存&#xff0c;当线程需要分配内存时可快速从其中获取&#xff0c;在Netty中用PoolThreadLocalCache来管理PoolThreadCache&#xff0c;它的数据结构如下&#xff1a; PoolThreadLocalCache相当…

【网络】UDP网络服务器简单模拟实现

【网络】UDP网络服务器简单模拟实现 文章目录 makefile服务端udpServerudpServer.ccudpServer.hpp初始化启动测试 客户端udpClientudpClient.ccudpClient.hpp初始化启动 整体代码 UDP的封装: UDP网络服务器模拟实现&#xff1a;主要分为makefile文件进行编译 UDP客户端&#xf…

Java开发 - 不知道算不算详细的分布式事务详解

前言 前日对JUC进行了一个深度总结&#xff0c;不过现在博主能记得的也不多了&#xff0c;只是这东西&#xff0c;不是看几遍写几遍就能完全记住的&#xff0c;功夫在平时&#xff0c;很多知识点都需要反复的看&#xff0c;不光要看&#xff0c;还要用&#xff0c;这样才能了解…

在CentOS上安装Jenkins并配置Docker

文章目录 步骤1 - 安装Java 11步骤2 - 安装Jenkins步骤3 - 安装Docker步骤4 - 配置Docker Cloud步骤 5 - 验证步骤 6 - 可能会遇到的问题 在本教程中&#xff0c;我们将展示如何在CentOS上安装Jenkins和Docker&#xff0c;并将它们配置在同一台机器上&#xff0c;使Jenkins能够…

《花雕学AI》WeTab+ChatGPT:让浏览器变成你的智能助手

引言&#xff1a; 浏览器是我们日常使用的最重要的工具之一&#xff0c;它可以帮助我们获取信息、娱乐、学习、工作等。但是&#xff0c;传统的浏览器往往不能满足我们的个性化需求&#xff0c;也不能给我们提供智能化的服务。那么&#xff0c;有没有一种浏览器可以让我们的体…

yoloV2细节改进

文章目录 1 v2 细节升级概述2 .网络结构特点3. 架构细节解读4. 基于聚类来选择先验框尺寸5. 偏移量计算方法6. 坐标映射与还原7 感受野8. 特征融合的改进其他知识点filter 是什么&#xff1f; 1 v2 细节升级概述 2 .网络结构特点 使用dropout&#xff0c;杀死部分神经元&#…

Java集合之单列集合

分类 集合分为单列集合&#xff08;Collection&#xff09;和双列集合&#xff08;Map&#xff09; 单列集合的体系结构 List集合和Set集合的区别 List系列集合&#xff1a;添加元素是有序的&#xff08;添加的顺序&#xff0c;而非数据的大小顺序&#xff09;、可重复、有索引…

为什么在Ubuntu系统使用附加驱动更新Nvidia显卡驱动不起作用

1. 硬件环境 CPU&#xff1a;AMD Ryzen 9 5950x 16-core processor 32 GPU&#xff1a;双GeForce RTX 3090 操作系统&#xff1a;Ubuntu 22.04.2 LTS 64 位 主板&#xff1a;ASUS的ROG CROSSHAIR VIII EXTREME 2. 问题描述 使用上图所示的附加驱动程序更新Nvidia显卡驱动&am…

恢复item2和oh-my-zsh的配置

1. 首先正常安装item2 2. 加载onedrive里的传家宝iterm2_default_profile.json&#xff0c;让iterm2的配置生效 2. 然后正常安装oh-my-zsh (官方步骤&#xff1a; sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)&q…

C# 学习abstract

abstract 顾名思义&#xff1a;抽象 从微软官方文档来看&#xff1a;abstract 修饰符指示被修改内容的实现已丢失或不完整。 abstract 修饰符可用于类、方法、属性、索引和事件。 在类声明中使用 abstract 修饰符来指示某个类仅用作其他类的基类&#xff0c;而不用于自行进行…

linux内核调试的几个方法

参考 以下内容&#xff1a; Linux 笔记&#xff1a; https://xuesong.blog.csdn.net/article/details/109522945?spm1001.2014.3001.5502 printk: printk在内核源码中用来记录日志信息的函数&#xff0c;只能在内核源码范围内使用。用法和printf非常相似&#xff1b; printk…

InsCode体验报告

文章目录 前言一、InsCode是什么&#xff1f;二、体验过程1.创建项目2.在线IDE3.运行和部署项目4.浏览和学习项目5.分享和协作项目6.支持AI助手 三、体验感受优点缺点 总结 官方宣传视频 InsCode-AI 前言 作为一个大三计算机专业的学生&#xff0c;我对编程有着浓厚的兴趣和热…

Triloga 的任务 — Satta 系列来袭!

谁战胜了这些凶兽&#xff0c;谁就获得了力量&#xff0c;让我们通过装备体现出来&#xff01;来自神秘洞穴的疯狂昆虫外壳&#xff0c;黄昏之地燃烧中的部落的骨质盔甲&#xff0c;以及深海的美妙灯光。 Triloga 的任务——Satta 系列已在 The Sandbox 市场平台上架&#xff1…

JVM(类的加载与ClassLoader、双亲委派机制)

文章目录 1. 类的生命周期2. 类的加载过程3. 类加载器&#xff08;classloader)3.1 类加载器的作用3.2 类加载器的分类(JDK8)3.3 双亲委派机制3.3.1 双亲委派机制优势 3.4 查看某个类的类加载器对象3.5 使用ClassLoader获取流 1. 类的生命周期 类在内存中完整的生命周期&#…

( “ 图 “ 之 并查集 ) 684. 冗余连接 ——【Leetcode每日一题】

❓684. 冗余连接 难度&#xff1a;中等 树可以看成是一个连通且 无环 的 无向 图。 给定往一棵 n 个节点 (节点值 1&#xff5e;n ) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间&#xff0c;且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n…

基于 EKS Fargate 搭建微服务性能分析系统

背景 近期 Amazon Fargate 在中国区正式落地&#xff0c;因 Fargate 使用 Serverless 架构&#xff0c;更加适合对性能要求不敏感的服务使用&#xff0c;Pyroscope 是一款基于 Golang 开发的应用程序性能分析工具&#xff0c;Pyroscope 的服务端为无状态服务且性能要求不敏感&…

Java阶段二Day14

Java阶段二Day14 文章目录 Java阶段二Day14复习前日知识点SpringFramework版本SpringFramework核心SpringFramework创建工程SpringFramework相关概念bean对象的创建过程xml配置文件中的标签 基于XML管理bean对象类型属性的注入数组类型属性注入集合类型属性注入p命名空间引入外…

ConMask: Open-World Knowledge Graph Completion

目录 Abstract Introduction Model Relationship-Dependent Content Masking Target Fusion Loss Function [1711.03438] Open-World Knowledge Graph Completion (arxiv.org) Abstract 引入一个名为ConMask的开放世界KGC模型&#xff0c;该模型学习实体名称和部分文本…

数据结构与算法基础-学习-23-图之邻接矩阵与邻接表

目录 一、定义和术语 二、存储结构 1、邻接矩阵 1.1、邻接矩阵优点 1.2、邻接矩阵缺点 2、邻接表 3、邻接矩阵和邻接表的区别和用途 3.1、区别 3.2、用途 三、宏定义 四、结构体定义 1、邻接矩阵 2、邻接表 3、网数据类型&#xff08;造测试数据&#xff09; 五…