JAVA小白学习日记Day10

news2024/9/9 0:43:46

1.线程锁

使用Runnable接口和Lambda表达式:

在 EasyThreadA 类的 mainA 方法中,通过创建 Runnable 实例 run,并使用Lambda表达式。 EasyThreadA::method 绑定到 run 上。然后创建两个线程 a 和 b,分别启动它们,它们会并发地执行 method 方法向共享的 list 中添加元素。这里的 list 是一个静态的 ArrayList,可能存在线程安全问题。
继承Thread类:

ThreadA 类继承自 Thread 类,重写了 run 方法,在其中向自己的 list 中添加元素。在 mainB 方法中创建了两个 ThreadA 实例 a 和 b,启动它们分别执行。每个线程拥有独立的 list,不存在直接的线程安全问题。
实现Runnable接口:

RunA 类实现了 Runnable 接口,在 run 方法中也向自己的 list 中添加元素。在 main 方法中创建了两个 RunA 实例作为 Thread 的任务,分别启动它们。每个 RunA 实例拥有独立的 list,不存在直接的线程安全问题。
需要注意的知识点:
多线程的实现方式:

可以通过实现 Runnable 接口或者继承 Thread 类来创建线程。推荐优先使用实现 Runnable 接口,因为Java中类只能单继承,而实现接口可以更灵活地组合多个接口实现不同的功能。
线程同步和等待:

使用 Thread.sleep(1000) 来模拟线程执行过程中的等待时间。在实际应用中,需要根据具体需求使用合适的线程同步机制,如 synchronized 关键字、Lock 接口、Atomic 类等来确保线程安全性。
Lambda表达式:

在 mainA 方法中使用了Lambda表达式 EasyThreadA::method,简化了匿名内部类的写法,提升了代码的简洁性和可读性。

package com.easy725;

import java.util.ArrayList;
import java.util.List;

public class EasyThreadA {
    static List list=new ArrayList();
    public static void method(){
        for (int i = 0; i <10 ; i++) {
            list.add(i+"A"+Thread.currentThread().getName());
        }
    }

    public static void mainA(String[] args) {
        Runnable run=EasyThreadA::method;
        Thread a=new Thread(run);
        Thread b=new Thread(run);
        a.start();
        b.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(list.size());
    }

    public static void mainB(String[] args) {
        ThreadA a=new ThreadA();
        ThreadA b=new ThreadA();
        a.start();
        b.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(a.list);
        System.out.println(b.list);
    }

    public static void main(String[] args) {
        RunA run=new RunA();
        Thread a=new Thread(run);
        Thread b=new Thread(run);
        a.start();
        b.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(run.list.size());
    }

}
class ThreadA extends Thread{
    public List list=new ArrayList();
    @Override
    public void run() {
        for (int i = 0; i <10 ; i++) {
            list.add("a");
        }
    }
}
class RunA implements Runnable{
    public List list=new ArrayList();
    @Override
    public void run() {
        for (int i = 0; i <10 ; i++) {
            list.add("a");
        }
    }
}

Lock对象的创建和使用:

Lock lock = new ReentrantLock();:创建了一个 ReentrantLock 类型的锁对象 lock。ReentrantLock 是可重入锁,支持公平和非公平性选择,默认是非公平锁(false)。

public void method() 方法中的逻辑:
if (lock.tryLock()) {:尝试获取锁。如果获取成功(返回 true),否则打印当前线程名并输出 "进入方法",然后输出 "结束方法",最后解锁 lock。
else {:如果尝试加锁失败,输出 "加锁未成功-----去执行别的代码",然后通过 Thread.sleep(1000) 模拟执行其他代码的情况,随后递归调用 method() 方法再次尝试获取锁。
main方法中的线程创建和启动:

Runnable run = new EasyThreadB()::method;:创建一个 Runnable 实例,通过方法引用绑定到 EasyThreadB 的 method() 方法上。
Thread a = new Thread(run); 和 Thread b = new Thread(run);:创建两个线程 a 和 b,它们共享同一个 run 实例,即同一个 method() 方法。
a.start(); 和 b.start();:启动两个线程并发执行 method() 方法。
需要注意的知识点:
Lock接口与ReentrantLock类:

Lock 接口提供了比传统的 synchronized 块和方法更广泛的锁定操作。ReentrantLock 是 Lock 接口的实现类,具有可重入特性,允许线程在同一个线程中多次获取同一个锁,避免死锁情况。
tryLock() 方法是 Lock 接口的一部分,尝试获取锁,如果成功则返回 true,否则立即返回 false,不会阻塞线程。这在避免线程长时间等待锁的情况下很有用。最后要unLock()方法解锁。
多线程同步与并发控制:

使用 ReentrantLock 可以更精确地控制多线程的并发访问,可以在需要的时候尝试获取锁,也可以实现公平性或非公平性的锁分配策略。
锁的释放应该始终放在 try 块的 finally 块中,以确保即使在获取锁期间发生异常,锁也能够被安全地释放。

死锁:

进程死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

线程死锁是指由于两个或者两个以上的线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。

死锁的产生还涉及到一些具体的条件,这些条件可以被看作是死锁产生的必要条件,包括:

互斥条件:资源不能被多个进程或线程同时访问,即资源是互斥的。
请求保持条件:进程或线程在请求资源时,已经持有其他资源,并且不愿意释放已经持有的资源。
不可剥夺条件:已经分配给进程或线程的资源,在未使用完之前不能被其他进程或线程剥夺。
循环等待条件:多个进程或线程之间形成一个循环等待链,每个进程或线程都在等待链中下一个进程或线程释放资源。

package com.easy725;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class EasyThreadB {
    //锁对象  Lock
    Lock lock=new ReentrantLock();//创建锁对象,在()中选择是否是公平锁,默认false(非公平锁)。
    public void method(){
        //lock.lock();//加锁
        //lock.trylock()  尝试加锁,加锁成功返回true,失败返回false。
        if (lock.tryLock()) {
            System.out.println(Thread.currentThread().getName() + "进入方法");

            System.out.println(Thread.currentThread().getName() + "结束方法");
            lock.unlock();//解锁
        }else {
            System.out.println("加锁未成功-----去执行别的代码");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            method();
        }
    }

    public static void main(String[] args) {
        Runnable run=new EasyThreadB()::method;
        Thread a=new Thread(run);
        Thread b=new Thread(run);
        a.start();
        b.start();
    }
}

读写锁 (ReentrantReadWriteLock):
ReentrantReadWriteLock 是一个锁容器,包含了读锁和写锁,能够提供比普通的互斥锁(如 ReentrantLock)更高的并发性。
读锁允许多个线程同时获取,适合对共享资源进行读取操作。
写锁是排他的,只允许一个线程获取,用于对共享资源进行写操作。
在代码中,通过 rrwl.readLock() 获取读锁,通过 rrwl.writeLock() 获取写锁,确保对共享资源的安全访问。

线程的启动和执行:
使用 Thread 类和 Runnable 接口创建多线程,通过 Thread.start() 启动线程,实现并发执行多个方法。
在 main 方法中,创建了多个读线程和写线程,分别调用 method() 和 methodWrite() 方法。
线程同步和锁的释放:
使用 lock.lock() 和 lock.unlock() 进行锁的获取和释放,确保在多线程环境下对共享资源的安全访问。
一般使用 try-finally 块确保在出现异常时能够正确释放锁,避免死锁或资源泄漏问题。

package com.easy725;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class EasyThreadC {
    //ReentrantReadWriteLock是个锁容器
    public static ReentrantReadWriteLock rrwl=new ReentrantReadWriteLock();
    public static ReentrantLock rl=new ReentrantLock();
    public static void method(){
        System.out.println(Thread.currentThread().getName()+"进入方法");
        Lock lock= rrwl.readLock();
        lock.lock();
        System.out.println(Thread.currentThread().getName()+"加锁成功----读锁");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"方法结束");
        lock.unlock();
    }
    public static void methodWrite(){
        System.out.println(Thread.currentThread().getName()+"进入方法");
        Lock lock= rrwl.writeLock();
        lock.lock();
        System.out.println(Thread.currentThread().getName()+"加锁成功----写锁");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"方法结束");
        lock.unlock();
    }

    public static void main(String[] args) {
        Runnable run=EasyThreadC::method;
        Runnable runWrite=EasyThreadC::methodWrite;
        Thread a=new Thread(run);
        a.start();
        Thread b=new Thread(run);
        b.start();
        Thread c=new Thread(run);
        c.start();
        Thread d=new Thread(run);
        d.start();
        Thread e=new Thread(run);
        e.start();
        Thread f=new Thread(runWrite);
        f.start();
        Thread g=new Thread(runWrite);
        g.start();
        Thread h=new Thread(runWrite);
        h.start();
        Thread i=new Thread(runWrite);
        i.start();
        System.out.println("main线程结束");
    }
}

同步和对象锁
synchronized 同步块:使用 synchronized (OBJ) 对象锁,确保多个线程在访问共享资源时的安全性。
wait 和 notify:通过 OBJ.wait() 和 OBJ.notify() 方法实现线程的等待和唤醒机制。
wait():使当前线程进入等待状态,并释放对象锁,直到其他线程调用对象的 notify() 或 notifyAll() 方法唤醒它。
notify() 和 notifyAll():唤醒等待在该对象上的一个或多个线程,使它们从等待池中进入就绪状态。
线程生命周期和状态
线程等待和重新运行:展示了线程如何在 wait() 被调用后进入等待状态,并在被唤醒后重新运行。
wait和sleep的区别:
wait是Object中定义的方法,可以由锁对象调用,让执行到该代码的线程进入到等待状态。
sleep是Thread类中定义的静态方法,也可以让执行到该行的线程进入等待状态。
区别:
1.sleep需要传入一个毫秒数,到达时间后会自动唤醒。wait不能自动唤醒,必须调用notify或者notifyALL方法。
2.sleep方法保持锁状态进入等待状态。wait方法会解除锁状态,其他线程可以进入运行。

package com.easy725;

public class EasyThreadD {
    public static final Object OBJ =new Object();

    public static void method(){
        System.out.println(Thread.currentThread().getName()+"进入方法");

        synchronized (OBJ){
            OBJ.notify();//唤醒一条被该锁对象wait的线程
            //OBJ.notifyAll();//唤醒全部被锁对象wait的线程
            System.out.println(Thread.currentThread().getName()+"进入同步代码块");
            try {
                try {
                    System.out.println(Thread.currentThread().getName()+"进入等待状态");
                    OBJ.wait();//让执行到改代码的线程进入到等待状态,在等待池中。
                    System.out.println(Thread.currentThread().getName()+"重新运行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"结束同步代码块");
            OBJ.notify();
        }
    }

    public static void main(String[] args) {
        Runnable run = EasyThreadD::method;
        Thread a=new Thread(run);
        a.start();
        Thread b=new Thread(run);
        b.start();
        Thread c=new Thread(run);
        c.start();
        Thread d=new Thread(run);
        d.start();
    }
    //wait和sleep的区别:
    //wait是Object中定义的方法,可以由锁对象调用,让执行到该代码的线程进入到等待状态。
    //sleep是Thread类中定义的静态方法,也可以让执行到该行的线程进入等待状态。
    //区别:
    //1.sleep需要传入一个毫秒数,到达时间后会自动唤醒。wait不能自动唤醒,必须调用notify或者notifyALL方法。
    //2.sleep方法保持锁状态进入等待状态。wait方法会解除锁状态,其他线程可以进入运行。
}

2.线程池

线程池:

ThreadPoolExecutor 是 Java 中用于管理线程池的类,通过它可以有效地重用线程,完成线程的创建管理和销毁工作。
在代码中,通过 ThreadPoolExecutor 的构造方法创建了一个线程池 tpe。
在这里,使用了一个 ArrayBlockingQueue 作为任务队列 qu,它限制了队列的容量为 12。
任务提交与执行:

线程池可以执行两种类型的任务:Runnable 和 Callable。
Runnable run = EasyExecuters::method; 定义了一个简单的 Runnable 任务,它会调用 method 方法。
tpe.execute(run); 提交 run 任务给线程池执行。
Callable<String> call = EasyExecuters::methodCall; 定义了一个 Callable 任务,它会调用 methodCall 方法,并返回一个结果。
Future<String> f = tpe.submit(call); 提交 call 任务给线程池执行,并获取一个 Future 对象,用于获取任务的执行结果。
任务执行结果获取:

System.out.println(f.get()); 使用 Future 对象的 get() 方法来获取 call 任务的执行结果。这是一个阻塞方法,会等待任务执行完毕并返回结果。
线程池的关闭:

tpe.shutdown(); 调用 shutdown() 方法关闭线程池。这会使线程池停止接受新的任务,并尝试将现有的任务执行完毕后关闭。

package com.easy725;

import java.util.Collection;
import java.util.Iterator;
import java.util.Queue;
import java.util.concurrent.*;

public class EasyExecuters {
    //线程池   池==重用
    //完成线程创建,管理,销毁工作
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        BlockingQueue qu = new ArrayBlockingQueue(12);
        ThreadPoolExecutor tpe=new ThreadPoolExecutor(5,
                10,
                10,
                TimeUnit.SECONDS,
                qu,
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        //线程任务:Runnable,Callable
        Runnable run=EasyExecuters::method;
        tpe.execute(run);
        Callable<String> call=EasyExecuters::methodCall;
        Future<String> f=tpe.submit(call);
        //f.cancel(true);//是否取消任务,一种中断线程的方式
        //tpe.submit(run);
        System.out.println(f.get());//会等待线程执行完毕
        //关闭线程池对象
        tpe.shutdown();
    }
    public static void method(){
        System.out.println(Thread.currentThread().getName()+"执行代码");

    }
    public static String methodCall(){
        System.out.println(Thread.currentThread().getName()+"执行代码call");
        return "callResult";
    }
}

1. 线程池的七个参数解释
在代码中,通过 ThreadPoolExecutor 的构造方法指定了以下七个参数:

corePoolSize: 核心线程数,即线程池中保持活跃的线程数量,即使它们是空闲的也会保留在池中。
maximumPoolSize: 最大线程数,线程池中允许的最大线程数量。当活跃线程数达到核心线程数,并且工作队列已满时,会创建新的线程,直到达到这个最大值。
keepAliveTime: 空闲线程的存活时间。超过核心线程数的线程在空闲超过这个时间后会被销毁,直到线程池的大小重新变为核心线程数为止。
unit: keepAliveTime 的时间单位。
workQueue: 工作队列,用于保存等待执行的任务。在本例中使用了 ArrayBlockingQueue,其容量为 12。
threadFactory: 线程工厂,用于创建新线程。
handler: 回绝策略,用于处理无法执行的任务。在本例中使用了 DiscardPolicy,即直接丢弃新任务而不抛出异常。

2.四种回绝策略(可以自定义)
AbortPolicy(默认):放弃该任务并会抛出一个异常,RejectedExecutionException。
CallerRunsPolicy:调用者执行,让传递任务的线程执行此任务。
DiscardOldestPolicy:放弃队列中时间最长的任务,不会抛出异常。
DiscardPolicy:直接放弃新的任务,不会抛异常。


3. 线程池的工作原理
当任务提交给线程池时,线程池会按照以下步骤处理任务:
如果当前活跃线程数小于核心线程数,创建新的线程来执行任务。
如果当前活跃线程数等于核心线程数,将任务加入工作队列。
如果工作队列已满但未达到最大线程数,创建新线程来执行任务。(占最大线程数)
如果工作队列已满且线程数已达到最大值,执行指定的回绝策略来处理新任务。


4. 内置的线程池对象
Java 提供了几种常见的内置线程池对象,可以根据应用的需要选择合适的线程池:

Executors.newCachedThreadPool(): 可根据需要(没有空闲就创建新线程)的线程池,空闲线程会在 60 秒后被回收。
Executors.newFixedThreadPool(int n): 固定大小的线程池,可以控制最大线程数。
Executors.newScheduledThreadPool(int corePoolSize): 支持定时和周期性的处理方案。
Executors.newSingleThreadExecutor(): 只有一个线程的线程池,确保所有任务按顺序执行。


5. 任务执行与线程池关闭
在代码中,通过 execute() 方法提交 Runnable 任务给线程池执行。
最后调用 shutdown() 方法关闭线程池,这会使线程池停止接受新任务,并尝试将已有的任务执行完毕后关闭。

package com.easy725;

import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.*;

public class EasyExecutersA {
    public static void main(String[] args) {
        //1.说明线程池的七个参数
        //2.四种回绝策略(可以自定义)
        //AbortPolicy(默认):放弃该任务并会抛出一个异常,RejectedExecutionException。
        //CallerRunsPolicy:调用者执行,让传递任务的线程执行此任务。
        //DiscardOldestPolicy:放弃队列中时间最长的任务,不会抛出异常。
        //DiscardPolicy:直接放弃新的任务,不会抛异常。
        //3.线程池的工作原理:
        //  任务放置在工作队列中
        //1>池中是否有空闲的线程,如果有,让该线程执行任务。
        //2>如果池中没有空闲的线程,判断线程数量是否达到核心线程数。
        //3>如果没有达到,创建新的线程执行任务,直到填满核心数。如果已经达到,优先在队列中存储,直到队列填满。
        //4>工作队列填满之后再添加新的任务,判断是否达到最大线程数,如果没有,创建新的线程执行任务,直到填满最大线程数。
        //5>如果填满最大线程数,队列也已经填满,没有空闲的线程,就执行回绝策略。
        //线程池中的线程达到(超过)核心线程数,超出的数量会根据存活时间进行销毁。直到数量达到核心线程数。如果线程的数量少于核心线程数,不会消亡。

        //java中内置的线程池对象
        //可以根据工作任务创建线程,如果没有空闲的线程,就创建新的线程。线程存活时间60s。
        //Executors.newCachedThreadPool();
        //设定最大线程数量
        //Executors.newFixedThreadPool(10);
        //提供定时运行的处理方案
        //Executors.newScheduledThreadPool(10);
        //创建一个具有单个线程的线程池,保证任务队列完全按照顺序执行
        //Executors.newSingleThreadExecutor();


        BlockingQueue queue=new ArrayBlockingQueue(12);
        ThreadPoolExecutor tpe=new ThreadPoolExecutor(5,
                8,10,
                TimeUnit.SECONDS,queue,
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardPolicy());
        Runnable run =()->{
            System.out.println(Thread.currentThread().getName()+"执行run方法");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"执行结束");
        };
        for (int i = 0; i <21 ; i++) {
            tpe.execute(run);
        }
        tpe.shutdown();
    }
}

3.枚举

枚举类 默认继承Enum类
首行必须枚举所有的实例。Enum的实例是可比较的(根据实例出来的顺序)。但是不可序列化,不能被new,克隆等操作。
当枚举中只有一个实例时,这个类就是单例的。

package com.easy725;

public enum  EasyColor {
    //枚举类 默认继承Enum类
    //首行必须枚举所有的实例。Enum的实例是可比较的(根据实例出来的顺序)。但是不可序列化,不能被new,克隆等操作。
    //当枚举中只有一个实例时,这个类就是单例的。
    RED,YELLOW,GREEN,BLUE,PINK;
    public void printColor(){
        System.out.println(this.name());
        System.out.println(this.ordinal());
    }

}
class Test{
    public static void main(String[] args) {
        EasyColor.PINK.printColor();
    }
}

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

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

相关文章

“数说”巴黎奥运会上的“中国智造”成果

引言&#xff1a;随着“中国智造”在欧洲杯上方兴未艾&#xff0c;在巴黎奥运会上&#xff0c;中国智造继续以多种形式和领域展现了其强大的实力和创新能力。以格力公开表示将为巴黎奥运村提供345台格力空调&#xff0c;为中国制造的清凉送至巴黎事件拉开中国制造闪亮巴黎奥运会…

CTF Web SQL注入 10000字详解

这里写目录标题 涉及的数据库知识unionorder bydatabase()information_schemalimit--空格注释replaceinto outfilelikeGROUP BYHAVINGGROUP BY、HAVING、WHERE之间的关系regexp 原理信息收集操作系统数据库判断注入点注入点类型POST注入数字型注入字符型注入搜索型注入Insert/u…

Debian12 安装Docker 用 Docker Compose 部署WordPress

服务器准备&#xff1a; 以root账号登录&#xff0c;如果不是root&#xff0c;后面指令需要加sudo apt update apt install apt-transport-https ca-certificates curl gnupg lsb-release添加GPG密钥&#xff0c;推荐国内源 curl -fsSL https://mirrors.aliyun.com/docker…

ArchLinux部署waydroid

在Arch Linux系统上部署Waydroid运行Android APP 文章目录 在Arch Linux系统上部署Waydroid运行Android APP1. 安装要求2. 本机环境3. 安装 Waydroid4. 网络配置5.注册Google设备6. 运行效果图 Waydroid是Anbox配合Haliun技术开发的LXC Android容器&#xff0c;可在GUN/Linux系…

C语言中的指针基础

文章目录 &#x1f34a;自我介绍&#x1f34a;地址&#x1f34a;C语言中的指针 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以&#xff1a;点赞关注评论收藏&#xff08;一键四连&#xff09;哦~ &#x1f34a;自我介绍 Hello,大家好&#xff0c;我是小珑也要变强&am…

Spring Boot 3 + Resilience4j 简单入门 + Redis Cache 整合

1. 项目结构 2. Maven依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.2</version><relativePath/> <!-- lookup parent from repository --&…

CSRF Token 原理

CSRF 攻击 CSRF 攻击成功的关键是&#xff0c;恶意网站让浏览器自动发起一个请求&#xff0c;这个请求会自动携带 cookie &#xff0c;正常网站拿到 cookie 后会认为这是正常用户&#xff0c;就允许请求。 防范 如果在请求中加一个字段&#xff08;CSRF Token&#xff09;&am…

C++笔记之指针基础

函数重载:(C++特性) 定义: C++允许函数重名,但是参数列表要有区分 在相同的作用域定义同名的函数,但是它们的参数要有所区分,这样的多个函数构成重载关系 objdump -d test.exe >log.txt 将test.exe反汇编并将结果重定向到log.txt 文件中 ,然后在 log.txt中找到定…

学习网络安全 为什么Linux首择Kali Linux? 以及如何正确的使用Kali Linux

1.什么是kali linux&#xff1f; Kali Linux是一款基于Debian的Linux发行版&#xff0c;主要用于网络安全测试和渗透测试。它由全球顶尖的安全专家和黑客社区维护开发&#xff0c;提供了丰富的工具和资源&#xff0c;用于测试安全性、漏洞利用和渗透测试。此外&#xff0c;Kal…

MySQL 性能调优

文章目录 一. MySQL调优金字塔1. 架构调优2. MySQL调优3. 硬件和OS调优4. 小结 二. 查询性能调优三. 慢查询1. 概念2. 优化数据访问3. 请求了不需要数据&#xff0c;怎么做4. 是否在扫描额外的记录5. 慢查询相关配置 & 日志位置6. 小结 四. 查询优化器五. 实现调优手段 一.…

24、Python之面向对象:责任与自由,私有属性真的有必要吗

引言 前面我们进一步介绍了类定义中属性的使用&#xff0c;今天我们对中关于属性私有化的话题稍微展开聊一下&#xff0c;顺便稍微理解一下Python设计的相关理念。 访问级别 在其他编程语言中&#xff0c;比如Java&#xff0c;关于类中的属性和方法通过关键字定义明确的访问级…

1、仓颉工程基础操作 cjpm

文章目录 1. 仓颉工程创建方式2. cjpm2.1 init 初始化工程2.2 run 运行工程 1. 仓颉工程创建方式 使用 cangjie studio 通过cangjie studio 创建 使用vscode插件 通过 VSCode 命令面板创建仓颉工程通过可视化界面创建仓颉工程 cjpm 注&#xff1a;具体使用参考官方文档&#…

探索分布式光伏运维系统的组成 需要几步呢?

前言 随着光伏发电的不断发展&#xff0c;对于光伏发电监控系统的需求也日益迫切&#xff0c;“互联网”时代&#xff0c;“互联网”的理念已经转化为科技生产的动力&#xff0c;促进了产业的升级发展&#xff0c;本文结合“互联网”技术提出了一种针对分散光伏发电站运行数据…

浅谈Devops

1.什么是Devops DevopsDev&#xff08;Development&#xff09;Ops&#xff08;Operation&#xff09; DevOps&#xff08;Development和Operations的混合词&#xff09;是一种重视“软件开发人员&#xff08;Dev&#xff09;”和“IT运维技术人员&#xff08;Ops&#xff09;”…

asp.net mvc 三层架构开发商城系统需要前台页面代完善

一般会后端开发&#xff0c;都不太想写前台界面&#xff0c;这套系统做完本来想开源&#xff0c;需要前台界面&#xff0c;后台已开发&#xff0c;有需求的朋友&#xff0c;可以开发个前端界面完善一下&#xff0c;有的话可以私聊发给我啊

The Llama 3 Herd of Models 第6部分推理部分全文

第1,2,3部分 介绍,概览和预训练 第4部分 后训练 第5部分 结果 6 Inference 推理 我们研究了两种主要技术来提高Llama 3405b模型的推理效率:(1)管道并行化和(2)FP8量化。我们已经公开发布了FP8量化的实现。 6.1 Pipeline Parallelism 管道并行 当使用BF16数字表示模型参数时…

VirtualBox创建共享磁盘

VirtualBox创建共享磁盘 目录 VirtualBox创建共享磁盘1、划分共享磁盘1.1、【管理】->【工具】->【虚拟介质管理】1.2、【创建】->【VDI&#xff08;VirtualBox 磁盘映像&#xff09;】->【下一步】1.3、【预先分配全部空间】->【下一步】1.4、【分配大小】->…

5、springboot3 vue3开发平台-后端- satoken 整合

文章目录 1. 为什么使用sa-token2. 依赖导入jichu2.1 基础依赖引入2.2 redis整合2.3 redis 配置&#xff0c; 使redis能支持中文存储 3. 配置4. 配置使用4.1 权限加载接口实现&#xff0c; 登录实现4.2 配置全局过滤器4.3 登录异常处理 5. 登录测试6. 用户session的获取 1. 为什…

MySQL索引与存储引擎、事物

数据库索引 是一个排序的列表&#xff0c;存储着索引值和这个值所对应的物理地址 无须对整个表进行扫描&#xff0c;通过物理地址就可以找到所需数据 是表中一列或者若干列值排序的方法 需要额外的磁盘空间 类型 普通索引 最基本的索引类型&#xff0c;没有唯一性之类的限制 创…

图不连通怎么办?

目录 1.问题 2.连通的相关概念 3.解决方案 C语言示例实现&#xff1a; 1.问题 无论是图的深度还是广度遍历都是从图的某一条边往下走&#xff0c;那么被孤立的结点怎么被遍历到呢&#xff1f; 2.连通的相关概念 连通&#xff1a;如果从V到W存在一条&#xff08;无向&#…