进程,线程,并发相关入门

news2025/1/15 21:04:58

进程与线程的简单理解

进程是一个独立的执行单元,它拥有自己的内存空间文件句柄和系统资源.进程是操作系统层面的,每个应用运行就是一个进程.进程之间通常是隔离的,它们不能直接访问对方的内存空间,必须通过进程间通信(IPC)机制来进行数据交换。

线程是进程内的执行单元,归属于进程,它共享进程的内存空间和资源。一个进程可以包含多个线程。但至少需要一个(普通)线程存活(守护线程不算).

并行与并发:

并行概念:并行是指多个进程或者多个线程同时执行任务,只是看起来并行,事实上没有真正的并行(暂时不存在真正意义上的并行,以后不知道).只是人类的感官觉得是并行.(即多核CPU中央处理器也无法达到真正并行)其实都是走走停停

并发:并发是指在相同的时间段内处理多个任务或操作的能力。这并不一定意味着这些任务实际上是同时执行的,而是它们在某个时间间隔内交替执行,以创建一种错觉,似乎它们在同时进行。可以是线程,也可以是进行,一般是指多个线程同时抢占同一个资源,导致错误结果.俗称并发安全问题

创建线程的第一种方式继承Thread,重写run方法

public class Thread1 {

    public static void main(String[] args) {
        Thread t1=new MyThread1();
        Thread t2=new MyThread2();
        t1.start();
        t2.start();
    }
}
//第一种方式:继承线程
class MyThread1 extends Thread{
    @Override
    public void run() {
        for(int i=0;i<100;i++){
            System.out.println("你是谁呀");
        }
    }
}
class MyThread2 extends Thread{
    @Override
    public void run() {
        for(int i=0;i<100;i++){
            System.out.println("查水表的");
        }
    }
}

局部内部类写法

public class Thread1 {

    public static void main(String[] args) {
        Thread t1=new Thread(){
            @Override
            public void run() {
                for(int i=0;i<100;i++){
                    System.out.println("你是谁呀");
                }
            }
        };
        Thread t2=new Thread(){
            @Override
            public void run() {
                for(int i=0;i<100;i++){
                    System.out.println("你是谁呀");
                }
            }
        };
        t1.start();
        t2.start();
    }
}

匿名内部类写法

public class Thread1 {

    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                for(int i=0;i<100;i++){
                    System.out.println("你是谁呀");
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                for(int i=0;i<100;i++){
                    System.out.println("你是谁呀");
                }
            }
        }.start();

    }
}

继承Thread的优点是写起来方便(特别是匿名内部类方式),缺点是Java是单继承的.继承了Thread之后无法再继承其他类.

第二点是线程和线程要干的活有着强耦合关系

创建线程的第二种方式.实现Runable接口.定义线程要执行的任务,将任务交给线程去执行

public class Thread2 {

    public static void main(String[] args) {
        //创建任务
        MyRunable1 my1=new MyRunable1();
        MyRunable2 my2=new MyRunable2();
        //创建线程 并让线程启动任务
        Thread t1=new Thread(my1);
        Thread t2=new Thread(my2);
        t1.start();
        t2.start();
    }
}
class MyRunable1 implements Runnable{

    @Override
    public void run() {
        for(int i=0;i<100;i++){
            System.out.println("你是谁呀");
        }
    }
}
class MyRunable2 implements Runnable{

    @Override
    public void run() {
        for(int i=0;i<100;i++){
            System.out.println("查水表的");
        }
    }
}

内部类写法

public class Thread2 {

    public static void main(String[] args) {

        //创建线程 并让线程启动任务
        Thread t1=new Thread(new Runnable(){

            @Override
            public void run() {
                for(int i=0;i<100;i++){
                    System.out.println("你是谁呀");
                }
            }
        });
        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<100;i++){
                    System.out.println("查水表的");
                }
            }
        });
        t1.start();
        t2.start();
    }
}

匿名内部类写法

public class Thread2 {

    public static void main(String[] args) {

        //创建线程 并让线程启动任务
       new Thread(new Runnable(){

            @Override
            public void run() {
                for(int i=0;i<100;i++){
                    System.out.println("你是谁呀");
                }
            }
        }).start();
       new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<100;i++){
                    System.out.println("查水表的");
                }
            }
        }).start();

    }
}

CurrentThread方法介绍:获取当前运行的线程

public class Thread3 {
    public static void main(String[] args) {
        /**
         * 线程提供了一个静态方法
         * static Thread currentThread()
         * 该方法用来获取运行这个方法的线程
         * main方法也是靠一个线程运行的.当JVM启动
         * 后会自动创建一个线程来执行main方法.称之为主线程
         */
        Thread thread = Thread.currentThread();
        System.out.println(thread);//Thread[main,5,main]

        dosome();

        Thread t1=new Thread(){
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                System.out.println("运行dosome方法的线程:"+t);//Thread[Thread-0,5,main]
            }
        };

        Thread t2=new Thread(){
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                System.out.println("运行dosome方法的线程:"+t);//Thread[Thread-1,5,main]
            }
        };
        t1.start();
        t2.start();
    }

    public static void dosome(){
        Thread thread = Thread.currentThread();
        System.out.println("运行dosome方法的线程:"+thread);//谁调用就是谁
    }
}

线程相关信息的获取

//线程提供了获取自身信息的相关方法
public class Thread4 {

    public static void main(String[] args) {
        //获取线程名
        Thread thread = Thread.currentThread();
        String name = thread.getName();
        System.out.println("name:"+name);

        //获取线程的唯一标识(id)   线程名可以重  但是id不能重
        long id = thread.getId();
        System.out.println("该线程的id是:"+id);

        Thread t1=new Thread(){
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                System.out.println("运行dosome方法的线程:"+t);//Thread[Thread-0,5,main]
                System.out.println("该线程的id是:"+t.getId());
            }
        };

        Thread t2=new Thread(){
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                System.out.println("运行dosome方法的线程:"+t);//Thread[Thread-0,5,main]
                System.out.println("该线程的id是:"+t.getId());
            }
        };
        t1.start();
        t2.start();
        //获取线程的优先级  1到10之间  默认都是5
        int priority = thread.getPriority();
        System.out.println("主线程的优先级:"+priority);

        boolean alive = thread.isAlive();
        System.out.println("线程是否还活者:"+alive);

        boolean interrupted = thread.isInterrupted();
        //中断就是让线程停了 一旦线程被中断(使用 interrupt() 方法中断),它的生命周期结束,不能重新启动.等待垃圾回收器回收
        System.out.println("线程是否被中断:"+interrupted);

        //守护线程或称之为后台线程
        boolean daemon = thread.isDaemon();
        System.out.println("线程是否为守护线程:"+daemon);
    }
}

一个个讲上面提到的方法

首先线程优先级 int priority = thread.getPriority();  1到10之间  默认都是5

线程优先级作用:干涉线程调度器工作 只能理论上尽量让该线程多获得CPU时间片,但是实际情况,说不好
理论上:线程优先级越高,获得CPU时间片的次数越多. 优先级用整数表示: 10最高    1最低    默认5

大于10或者小于1都会报错

理论来讲应该是优先级高的先输出完,然后是默认的,然后是优先级最低的,但是实际效果是不一定

调整线程优先级的结果未必理想,但是这是唯一可以改变争取或降低CPU时间片的方式

//线程优先级
public class PriorityDemo {
    public static void main(String[] args) {
        //线程优先级作用:干涉线程调度器工作 只能理论上尽量让该线程多获得CPU时间片,但是实际情况,说不好
        //理论上:线程优先级越高,获得CPU时间片的次数越多. 优先级用整数表示: 10最高    1最低    默认5

        Thread max=new Thread(){
            @Override
            public void run() {
                for(int i=0;i<10000;i++){
                    System.out.println("max");
                }
            }
        };
        Thread min=new Thread(){
            @Override
            public void run() {
                for(int i=0;i<10000;i++){
                    System.out.println("min");
                }
            }
        };
        Thread norm=new Thread(){
            @Override
            public void run() {
                for(int i=0;i<10000;i++){
                    System.out.println("norm");
                }
            }
        };
        //如果设置的优先级>最高(10) 或者<(1)都会报错   抛IllegalArgumentException
        //max.setPriority(10);
        max.setPriority(Thread.MAX_PRIORITY);//用常量   设置优先级

        min.setPriority(Thread.MIN_PRIORITY);

        norm.setPriority(Thread.NORM_PRIORITY);

        max.start();
        min.start();
        norm.start();
    }
}

sleep阻塞

线程提供了一个静态方法:static void sleep(long ms)

使运行这个方法的线程阻塞指定毫秒.超时后该线程会自动回到Runnable状态,

等待再次获得CPU时间片运行 这个和计时器差不多

public class Thread5 {

    public static void main(String[] args) {
        System.out.println("程序开始了");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("程序结束了");
    }
}

小案例:控制太输入倒计,每个1秒,到0停止

java中一般会引起线程阻塞的方法都要求捕获InterruptedException中断异常

public class Thread6 {
    public static void main(String[] args) {
        System.out.println("输入数字:");
        Scanner scanner=new Scanner(System.in);
        String line = scanner.nextLine();

        Integer num=Integer.parseInt(line);
        for(;num>0;num--){
            System.out.println(num);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("结束");
    }
}

sleep阻塞demo2

sleep方法要求必须处理中断异常,原因在于当一个线程调用了sleep方法处于阻塞状态的过程中其他线程中若调用了它的interupt()方法中断时,它就会在sleep方法中抛出中断异常.这时并非是将这个线程直接中断,而是中断了它的阻塞状态.

  

public class Thread7 {

    public static void main(String[] args) {
        Thread lin=new Thread(){
            @Override
            public void run() {
                //while(!Thread.currentThread().isInterrupted()) {
                    System.out.println("林:刚美完容,睡一觉");
                    try {
                        Thread.sleep(10000000);
                    } catch (InterruptedException e) {
                        System.out.println("林:干嘛呢?干嘛呢?");
                    }
                //}
                System.out.println("林:醒了");
            }
        };

        Thread huang=new Thread(){
            @Override
            public void run() {
                System.out.println("黄:开始砸墙!");
                for(int i=0;i<5;i++){
                    System.out.println("黄:80!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("咣当!");
                System.out.println("黄:搞定!");


                //中断lin线程
                lin.interrupt();//这里注意:JDK8之前这样写报错,报错原因JDK8之前要求局部内部类中要使用方法内的局部变量,那个变量前要加final

            }
        };
        lin.start();
        huang.start();
    }
}

守护线程

守护线程又称后台线程,默认创建的线程都是普通线程或称为前台线程,线程提供了一个

方法:void setDaemon(boolean on)

只有调用该方法并传入为true时,该线程才会被设置为守护线程.

守护线程在使用上于普通线程没有差别,但是在结束时机上有一个区别,即:线程结束时所有正在运行的守护线程都会被强制停止.

进程的结束:当一个进程中所有的普通线程都结束时,进程即结束

GC就是一个守护线程

public class Thread8 {

    public static void main(String[] args) {
        Thread rose=new Thread(){
            @Override
            public void run() {
                for(int i=0;i<5;i++){
                    System.out.println("rose:let me go!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("rose:啊啊啊啊啊啊啊啊啊!!!!!");
            }
        };

        Thread jack=new Thread(){
            @Override
            public void run() {
                while(true){
                    System.out.println("jack:you jump! I jump!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        Thread disanzhe=new Thread(){
            @Override
            public void run() {
                for(int i=0;i<10;i++) {
                    System.out.println("disanzhe:吃瓜!看热闹");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        rose.start();
        jack.setDaemon(true);//设置为守护线程,要在启动前设置  有几个线程启动就守护几个线程
        jack.start();
        disanzhe.start();
        //原先的观点:main方法结束,程序退出.以后的观点就是:当所有前台线程结束,进程结束.才算结束
        System.out.println("main方法结束");//这里是main先结束


        //这样的话,守护线程永远不会结束,原因是main线程还一致活者
//        while(true){
//
//        }
    }
}

join:协调线程之间的同步运行

线程提供了一个方法:

void join()

该方法可以协调线程之间的同步运行

同步与异步:

同步:运行有顺序

异步运行:运行代码无顺序,多线程并发运行就是异步运行

多线程是异步运行的,但是有时候我们也需要他们同步---->利用join

public class Thread9 {
    private static boolean isFinish=false;//这个放在方法内编译不通过
    public static void main(String[] args) {

        int a=1;
        Thread download=new Thread(){
            @Override
            public void run() {
                System.out.println("down:开始下载图片");

                for(int i=1;i<=100;i++){
                    System.out.println("down:"+i+"%");
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("down:下载图片完毕");
                isFinish=true;

            }
        };
        Thread show=new Thread(){
            @Override
            public void run() {
                System.out.println("show:开始显示图片");
                //加载图片前应先等待下载线程将图片下载完毕
                try {
                    /**
                     * show线程里调用download.join()方法后
                     * 就进入了阻塞状态,知道download线程的run方法执行完毕才会解除
                     */
                    //这样可以使用应该和线程上下文有关
                    download.join();//在show的线程里写  download.join() 就是等待download线程完毕
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(!isFinish){
                    throw new RuntimeException("加载图片失败");
                }
                System.out.println("show:显示图片完毕");
            }
        };

        download.start();
        show.start();
    }
}

wait    用锁对象.wait()

wait()方法其实主要做三件事:

①把当前线程放进等待队列中

②释放锁

③被其他线程唤醒时,尝试重新获取锁

wait() 无参数版本

wait(long) 指定最大等待时间,单位毫秒

wait(long,int) 精度更高,前面是毫秒,后面是纳秒

notifyAll():唤醒加了相同锁的所有线程

wait和sleep其实是没有可比性的,因为一个是用于线程之间的通信的,一个是让线程阻塞一段时间。这两个方法设计的初心是不同的,一个是单纯为了让线程进行阻塞等待而休眠一段时间,而一个是为了解决线程的执行顺序的问题。最明显的区别就是wait需要搭配锁使用,而sleep不需要。wait 是 Object 的方法 sleep 是 Thread 的静态方法。他们唯一的相同点就是都可以让线程进入阻塞等待状态。
 

但是自测sleep无法唤醒,只能interrupt中断(不是很清楚)

notify:用锁对象.notify() 唤醒

public class Thread7 {

    public static void main(String[] args) {
        Object o=new Object();
        Thread lin=new Thread(){
            @Override
            public void run() {
                //while(!Thread.currentThread().isInterrupted()) {
                    System.out.println("林:刚美完容,睡一觉");
                    synchronized (o) {
                        try {
                            //Thread.sleep(1000000);
                            o.wait();
                        } catch (InterruptedException e) {
                            System.out.println("林:干嘛呢?干嘛呢?");
                        }
                    }
                //}
                System.out.println("林:醒了");
            }
        };

        Thread huang=new Thread(){
            @Override
            public void run() {
                System.out.println("黄:开始砸墙!");
                for(int i=0;i<5;i++){
                    System.out.println("黄:80!");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("咣当!");
                System.out.println("黄:搞定!");
                //唤醒该锁线程,可以在线程里,方法里
                synchronized (o){
                    o.notify();
                }

                //中断lin线程
                //lin.interrupt();//这里注意:JDK8之前这样写报错,报错原因JDK8之前要求局部内部类中要使用方法内的局部变量,那个变量前要加final

            }
        };
        lin.start();
        huang.start();
    }
}
public class Thread10 {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();

        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    lock.wait();
                    System.out.println("Thread1被唤醒了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println("出错了");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                try {
                    lock.wait();
                    System.out.println("Thread2被唤醒了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println("出错了");
                }
            }
        });

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

        Thread.sleep(5000);
        synchronized (lock){
            //lock.notify();
            lock.notifyAll();
        }
    }
}

并发安全问题

并发会出现的情况

多线程并发的安全问题

产生:当多个线程并发操作同一资源时,由于线程切换时机的不确定性,会导致

执行操作资源的代码顺序未按照设计顺序执行,出现操作混乱的情况.

严重时可能导致系统瘫痪.

解决:将并发操作同一资源改为同步操作,即:有先后顺序的操作

public class SyncDemo1 {

    public static void main(String[] args) {
        Table table=new Table();
        Thread t1=new Thread(){
            @Override
            public void run() {
                while(true){
                    int bean=table.getBean();
                    Thread.yield();
                    System.out.println(getName()+":"+bean);
                }
            }
        };

        Thread t2=new Thread(){
            @Override
            public void run() {
                while(true){
                    int bean=table.getBean();
                    Thread.yield();
                    System.out.println(getName()+":"+bean);
                }
            }
        };

        t1.start();
        t2.start();
        
    }
}
class Table{
    //20个豆子
    private int bean=20;

    public int getBean(){
        if(bean==0){
            throw new RuntimeException("没有豆子了");
        }
        //模拟线程执行到这里没有时间了 它是告诉线程调度器,愿意主动让出CPU时间片,不能确保线程一定会让出
        Thread.yield();
        return bean--;
    }
}

解决办法:加同步锁

在getBean方法上加锁 synchronized   对方法枷锁  就是给对象枷锁

但是在方法上加上synchronized会降低效率

那么用同步块缩小控制范围

同步块:语法

synchronized(同步监视器对象){

        需要同步运行的代码片段

}

同步块可以更精准的控制需要同步运行的代码片段.有效的缩小同步范围可以在保证并发安全

的前提下提高代码并发运行的效率

使用同步块控制多线程同步运行必须要求这些线程看到的同步监视器对象为[同一个]

有效缩小同步范围可以在保证

public class SyncDemo2 {

    public static void main(String[] args) {
        Shop shop=new Shop();
        Thread t1=new Thread(){
            @Override
            public void run() {
                shop.buy();
            }
        };
        Thread t2=new Thread(){
            @Override
            public void run() {
                shop.buy();
            }
        };
        t2.start();
    }
}
class Shop{
    public void buy(){
        try {
            Thread t=Thread.currentThread();
            System.out.println(t.getName()+":正在挑衣服");
            Thread.sleep(5000);

            synchronized (this) {
                System.out.println(t.getName() + ":正在试衣服");
                Thread.currentThread();
            }

            System.out.println(t.getName()+":结账离开");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

静态方法加synchronized一定具有同步效果,锁的是类对象 Class的实例

当静态方法加了synchronized,已经和对象无关了,无论你创建了多少个对象,

必定会有同步效果

public class SyncDemo3 {
    public static void main(String[] args) {

        Foo f1=new Foo();
        Foo f2=new Foo();

        Thread t1=new Thread(){
            @Override
            public void run() {
                //Foo.dosome();
                f1.dosome();
            }
        };

        Thread t2=new Thread(){
            @Override
            public void run() {
                //Foo.dosome();
                f2.dosome();
            }
        };

        t1.start();
        t2.start();
    }
}
class Foo{
    public synchronized static void dosome(){
        Thread t=Thread.currentThread();
        System.out.println(t.getName()+":正在运行dosome方法");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(t.getName()+":运行dosome方法完毕");
    }
}

synchronized的另外一种作用:

synchronized称为同步锁,还可以帮助维护一种关系,互斥关系

有你没我,有我没你.比如有A方法和B方法,我们希望出现的情况是:

调用A方法就不能调用B,调用B方法就不能调用A,就是不能同时干两个方法

比如咽下去东西和喘气就是互斥的,不能同时干

如何在程序里实现互斥关系,希望互斥的代码用synchronized锁上,然后互斥的代码使用的锁是同一个,他们之间就是互斥关系

互斥锁:

当多个代码片段被synchronized块修饰后,这些同步块的同步监听器对象又是同一个时,这些代码片段就是互斥的.多个线程不能同时在这些方法中运行.

注意:不一定是两个方法,可以是两个代码块,只要锁的对象是同一个,就有互斥效果

public class SyncDemo4 {

    public static void main(String[] args) {
        Boo boo=new Boo();
        Thread t1=new Thread(){
            @Override
            public void run() {
                boo.methodA();
            }
        };
        Thread t2=new Thread(){
            @Override
            public void run() {
                boo.methodA();
            }
        };
        t1.start();
        t2.start();
    }
}
class Boo{
    public synchronized void methodA(){
        Thread t=Thread.currentThread();
        try {
            System.out.println(t.getName()+":正在运行A方法");
            Thread.sleep(5000);
            System.out.println(t.getName()+":运行A方法结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void methodB(){
        Thread t=Thread.currentThread();
        try {
            System.out.println(t.getName()+":正在运行B方法");
            Thread.sleep(5000);
            System.out.println(t.getName()+":运行B方法结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

关于Thread的静态方法 static void yield()

该方法用于使当前线程主动让出当次CPU时间片回到Runable状态,等待分配时间片

上面这图就是线程运行状态

线程.start()之后进入可运行状态(并不是立刻执行,而是交给线程调度器,进入可运行状态,线程调度器把CPU时间分配给谁,谁先执行,不一定说先start的就一定先执行),当获得CPU时间之后开始运行,CPU时间片用完了,回到可运行状态,等待线程调度分配CPU时间片,任务完成(run方法执行完毕)等待被回收.线程调度器无序分配CPU时间片,只能说尽量分配获得CPU时间片的时间均匀,但不保证

线程有三种阻塞状态,分别是IO阻塞     Sleep阻塞   Wait阻塞  阻塞的直观表现就是卡了

IO阻塞常见的比如说Scanner      Sleep阻塞比如说Thread.sleep  

执行某些特殊代码,让线程进入阻塞状态

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

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

相关文章

java微服务项目整合skywalking链路追踪框架

skywalking官网网址&#xff1a;Apache SkyWalking 目录 1、安装skywalking 2、微服务接入skywalking 3、skywalking数据持久化 1、安装skywalking 下载skywalking&#xff0c;本篇文章使用的skywalking版本是8.5.0 Index of /dist/skywalkinghttps://archive.apache.org/…

Java中代理的实现方式

Java中代理的实现方式 1. 静态代理2. JDK动态代理3. CGLIB动态代理扩展 在Java中&#xff0c;有多种方式可以实现代理&#xff0c;包括&#xff1a; 静态代理&#xff1a; 创建一个代理类&#xff0c;实现与目标类相同的接口或继承与目标类相同的父类。在代理类中持有一个目标类…

6.2、Flink数据写入到Kafka

目录 1、添加POM依赖 2、API使用说明 3、序列化器 3.1 使用预定义的序列化器 3.2 使用自定义的序列化器 4、容错保证级别 4.1 至少一次 的配置 4.2 精确一次 的配置 5、这是一个完整的入门案例 1、添加POM依赖 Apache Flink 集成了通用的 Kafka 连接器&#xff0c;使…

Python:函数调用的实参

相关阅读 Python专栏https://blog.csdn.net/weixin_45791458/category_12403403.html 调用就是附带可能为空的一系列参数来执行一个可调用对象 &#xff08;例如函数&#xff09;&#xff0c;它的语法的BNF范式如下所示&#xff0c;有关BNF范式的规则&#xff0c;可以参考之前…

无涯教程-JavaScript - CEILING.MATH函数

描述 CEILING.MATH函数将数字四舍五入到最接近的整数或最接近的有效倍数。 Excel CEILING.MATH函数是Excel中的十五个舍入函数之一。 语法 CEILING.MATH (number, [significance], [mode])争论 Argument描述Required/OptionalNumberNumber must be less than 9.99E307 and …

运维自动化:提高效率的秘诀

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

从一到无穷大 #16 ByteSeries,思考内存时序数据库的必要性

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 引言 在[3]中我基于Gorilla讨论了时序数据库设置cache的可行性&#xff0c;最后得出结论&…

许可分析 license分析 第十章

许可分析是指对软件许可证进行详细的分析和评估&#xff0c;以了解组织内部对软件许可的需求和使用情况。通过许可分析&#xff0c;可以帮助组织更好地管理和优化软件许可证的使用。以下是一些可能的许可分析方法和步骤&#xff1a; 软件许可证供应商管理&#xff1a;评估和管理…

CSS 浮动布局

浮动的设计初衷 float: left/right/both;浮动是网页布局最古老的方式。 浮动一开始并不是为了网页布局而设计&#xff0c;它的初衷是将一个元素拉到一侧&#xff0c;这样文档流就能够包围它。 常见的用途是文本环绕图片&#xff1a; 浮动元素会被移出正常文档流&#xff0c;…

Redis集群总结

Redis&#xff0c;作为一款开源的、内存中的数据结构存储系统&#xff0c;以其出色的性能和丰富的数据结构在业界赢得了广泛的认可。然而&#xff0c;当我们面临大量数据和高并发请求时&#xff0c;单个 Redis 实例可能无法满足我们的需求。这时&#xff0c;我们就需要使用到 R…

Kubernetes实践:从入门到实践

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

认识Git的工作区、暂存区与版本库

使用 git init 命令在 gitcode 文件夹下创建如下图所示的Git仓库。现在思考这样一个问题&#xff1a;gitcode目录下创建的README文件可以直接被git管理和追踪吗&#xff1f; 答案是否定的&#xff0c;因为只有 Git 本地仓库中的文件才可以被版本控制。什么&#xff1f;难道当前…

内网隧道代理技术(二十七)之 DNS隧道介绍

DNS隧道介绍 DNS协议介绍 域名系统(Domain Name System,缩写:DNS)是互联网的一项服务。它作为将域名和IP地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。DNS使用TCP和UDP端口53。当前,对于每一级域名长度的限制是63个字符,域名总长度则不能超过253个字符…

第二篇------Virtual I/O Device (VIRTIO) Version 1.1

上篇文章&#xff1a;https://blog.csdn.net/Phoenix_zxk/article/details/132917657 篇幅太大&#xff0c;所以分开写&#xff0c;接下来续上 4.3.3.2.1 设备要求&#xff1a;Guest->Host 通知 设备必须忽略 GPR2 的位 0-31&#xff08;从左边数&#xff09;。这样可以使…

Eclipse开源代码下载

当前插件开发&#xff0c;需要修改eclipse源码&#xff0c;如需要修改remote相关的代码&#xff0c;所以需要下载相关源码。网上大多资料都说的不清不楚的&#xff0c;也可能我太小白&#xff0c;不明白&#xff0c;反正就是折腾了一两天才感觉有点思路&#xff0c;改如何找源码…

Linux安全加固:保护你的服务器

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

基于springboot+vue的问卷调查系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

聊天机器人

收集窗帘相关的数据 可以用gpt生成&#xff0c;也可以用爬虫 图形化界面 gradio 向量数据库 faiss python代码 import gradio as gr import random import timefrom typing import Listfrom langchain.embeddings.openai import OpenAIEmbeddings from langchain.vectorstor…

央媒发稿不能改?媒体发布新闻稿有哪些注意点

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 “央媒发稿不能改”是媒体行业和新闻传播领域的普遍理解。央媒&#xff0c;即中央主要媒体&#xff0c;是权威性的新闻源&#xff0c;当这些媒体发布新闻稿或报道时&#xff0c;其他省、…

服务器监控工具:选择与应用

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…