线程的状态及常用方法

news2024/11/15 21:45:06

1. 线程的状态

  • 在Java程序中,一个线程对象通过调用start()方法启动线程,并且在线程获取CPU时,自动执行run()方法。run()方法执行完毕,代表线程的生命周期结束。
  • 在整个线程的生命周期中,线程的状态有以下6种:
    • New:新建状态,新创建的线程,此时尚未调用start()方法;
    • Runnable:运行状态,运行中的线程,已经调用start()方法,线程正在或即将执行run()方法;
    • Blocked:阻塞状态,运行中的线程,在等待竞争锁时,被阻塞,暂不执行;
    • Waiting:等待状态,运行中的线程,因为join()等方法调用,进入等待;
    • Timed Waiting:计时等待状态,运行中的线程,因为执行sleep(等待毫秒值)join(等待毫秒值)等方法,进入计时等待;
    • Terminated:终止状态,线程已终止,因为run()方法执行完毕。
  • 当线程启动后,它可以在Runnable、Blocked、Waiting和Timed Waiting这几个状态之间切换,直到最后变成Terminated状态,线程终止

  • 线程终止的原因有:
    • 线程正常终止:run()方法执行到return语句返回;
    • 线程意外终止:run()方法因为未捕获的异常导致线程终止;
    • 对某个线程的Thread实例调用stop()方法强制终止(宇宙超级无敌强烈不推荐);

2. 线程的插队:join( )方法

2.1 join( )方法的作用
    • t.join()方法会使当前线程( 主线程 或者调用t.join()的线程 )进入等待池,并等待 线程t 执行完毕后才会被唤醒。此时,并不影响同一时刻处在运行状态的其他线程。

示例:

myThread.join()被主线程调用,则主线程进入WAITING或者TIMED_WAITING(调用myThread.join(long millis))等待状态,主线程Main必须等子线程myThread执行完毕后才能继续执行。当子线程myThread执行完毕后,进入TERMINATED终止状态,会自动调用notifyAll()方法,唤醒主线程,主线程重新进入RUNNABLE运行状态,继续执行;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("主线程Main:开始执行,即将创建并调用子线程");

        // 创建并启动子线程
        MyThread myThread = new MyThread();
        myThread.start();

        // 主线程调用myThread子线程的join()方法
        myThread.join(); // 子线程插队,插入到当前线程main的执行序列前
        
        System.out.println("主线程Main:当子线程myThread执行完毕后,主线程Main再执行");
    }
}
public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("子线程:开始执行");
        int sencondValue = (int)(Math.random()*1000);
        try {
            Thread.sleep(sencondValue);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("子线程:结束执行,耗时"+sencondValue+"毫秒");
    }
}
2.2 join( )方法的实现原理
    • join()方法的底层是利用wait()方法实现;
    • join()方法是一个synchronized同步方法,当主线程调用 线程t.join( )方法时,主线程先获得了 线程t对象 的锁,随后进入join()方法,调用 线程t对象 的wait()方法,使主线程进入了 线程t对象 的等待池;
    • 等到 线程t 执行完毕之后,线程在TERMINATED终止状态的时候会自动调用自身的notifyAll()方法,来唤醒所有处于等待状态的线程:这个机制在隐藏在native本地方法中,由一个C++实现的方法ensure_join()函数实现。在该函数的尾部,执行了lock.notify_all(thread);,相当于调用了notifyAll()方法。
static void ensure_join(JavaThread*thread) {
    Handle threadObj(thread, thread -> threadObj());
    ObjectLocker lock(threadObj, thread);
    thread -> clear_pending_exception();
    java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
    java_lang_Thread::set_thread(threadObj(), NULL);
    //下行执行了notifyAll()操作
    lock.notify_all(thread);
    thread -> clear_pending_exception();
}
  • 综上所述:join()方法实际上是通过调用wait()方法, 来实现同步的效果的。
    • 例如:A线程中调用了B线程的join()方法,则相当于A线程调用了B线程的wait()方法,在调用了B线程的wait()方法后,A线程就会进入WAITING或者TIMED_WAITING等待状态,因为它相当于放弃了CPU的使用权。
  • 注意:join(0)的意思不是A线程等待B线程0秒,而是A线程等待B线程无限时间,直到B线程执行完毕:即join(0)=join();
public class Thread implements Runnable
    public final void join() throws InterruptedException {
       join(0);
    }

	public final synchronized void join(long millis) throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                // 无限等待
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                // 计时等待
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }
}

阅读代码,分析运行结果:

public class Main {
    
    private static void printWithThread(String content) {
        System.out.println("[" + Thread.currentThread().getName() + "线程]: " + content);
    }
    
    public static void main(String[] args) {
        printWithThread("开始执行main方法");
        
        Thread myThread = new Thread(new Runnable() {
            @Override
            public void run() {
                printWithThread("我在自定义的线程的run方法里");
                printWithThread("我马上要休息1秒钟, 并让出CPU给别的线程使用.");
                try {
                    Thread.sleep(1000);
                    printWithThread("已经休息了1秒, 又重新获得了CPU");
                    printWithThread("我休息好了, 马上就退出了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        
        try {
            myThread.start();
            printWithThread("我在main方法里面, 我要等下面这个线程执行完了才能继续往下执行.");
            myThread.join();
            printWithThread("我在main方法里面, 马上就要退出了.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

[main线程]: 开始执行main方法
[main线程]: 我在main方法里面, 我要等下面这个线程执行完了才能继续往下执行.
[Thread-0线程]: 我在自定义的线程的run方法里
[Thread-0线程]: 我马上要休息1秒钟, 并让出CPU给别的线程使用.
[Thread-0线程]: 已经休息了1秒, 又重新获得了CPU
[Thread-0线程]: 我休息好了, 马上就退出了
[main线程]: 我在main方法里面, 马上就要退出了.

运行结果分析:

我们在main方法中调用了myThread.join(),上面这段代码有两个线程:一个是执行main方法的main线程,一个是我们自定义的Thread-0线程。

  • Thread-0线程是myThread对象代表的子线程;
  • main线程在等Thread-0线程的终止,因为我们在main方法中调用了myThread.join();
  • Thread-0线程中途让出了CPU, main线程还是必须等到其执行完毕了才能继续往下执行;

如果将myThread.join()改为myThread.join(500),代表main线程最多等500毫秒(0.5秒),运行结果如下:

[main线程]: 开始执行main方法
[main线程]: 我在main方法里面, 我要等下面这个线程执行完了才能继续往下执行.
[Thread-0线程]: 我在自定义的线程的run方法里
[Thread-0线程]: 我马上要休息1秒钟, 并让出CPU给别的线程使用.
[main线程]: 我在main方法里面, 马上就要退出了.
[Thread-0线程]: 已经休息了1秒, 又重新获得了CPU
[Thread-0线程]: 我休息好了, 马上就退出了

运行结果分析:

main线程在等Thread-0线程的过程中,设置等待500毫秒,而Thread-0线程休眠1000毫秒,所以main线程先执行输出,Thread-0线程休眠结束后,恢复执行;

2.3 join( )方法和sleep( )方法的区别
    • 两个方法都可以实现类似"线程等待"的效果,但是仍然有区别;
    • join()是通过在内部使用synchronized + wait()方法来实现的,所以join()方法调用结束后,会释放锁;
    • sleep()休眠没有结束前,不会释放锁;

3. 线程的中断:interrupt( )方法

如果线程需要执行一个长时间任务,就可能需要能中断线程。中断线程就是其他线程给该线程发一个信号,该线程收到信号后结束执行run()方法,使得自身线程能立刻结束运行。

例如:假设从网络下载一个100M的文件,如果网速很慢,用户等得不耐烦,就可能在下载过程中点“取消”,这时,程序就需要中断下载线程的执行。

中断一个线程非常简单,只需要在其他线程中对目标线程调用interrupt()方法,目标线程需要反复检测自身状态是否是interrupted状态,如果是,就立刻结束运行。

3.1 interrupt( )方法的作用

interrupt()方法的作用是设置该线程的中断状态为true,线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于中断状态。线程会不时地检测这个中断状态值,以判断线程是否应该被中断(中断状态值是否为true)。

3.2 interrupt( )方法的原理

interrupt()方法只是改变中断状态,不会像stop()中断一个正在运行的线程。支持线程中断的方法(Thread.sleep() 、join()、wait()等方法)就是在监视线程的中断状态,一旦发现线程的中断状态值被置为“true”,就会抛出线程中断的异常InterruptedException,给WAITING或者TIMED_WAITING等待状态的线程发出一个中断信号,线程检查中断标识,就会以退出WAITING或者TIMED_WAITING等待状态;

注意事项:

  • 线程被Object.wait(), Thread.join()和Thread.sleep()三种方法阻塞或等待,此时调用该线程的interrupt()方法,那么该线程将抛出一个 InterruptedException中断异常,从而提前终结被阻塞状态。
  • 如果线程没有被阻塞或等待,调用 interrupt()将不起作用,直到执行到wait(),sleep(),join()等方法进入阻塞或等待时,才会抛出 InterruptedException异常;

案例1:子线程休眠时,可以通过interrupt()中断子线程;

public class Main {
	public static void main(String[] args) {
	    // 创建子线程
	    Thread thread = new Thread() {
	        public void run() {
	            System.out.println("子线程开始执行,进入RUNNABLE状态");
	            try {
	                // 子线程休眠6秒,进入TIMED_WAIT计时等待状态
	                Thread.sleep(1000 * 6); 
	            } catch (InterruptedException e) {
	                e.printStackTrace();
	                System.out.println("子线程中断,进入TERMINATED状态");
	                return;
	            }
	            System.out.println("子线程结束执行,进入TERMINATED状态");
	        }
	    };
	    
	    // 启动子线程
	    thread.start();
		
	    // main主线程休眠5秒
	    try {
	        Thread.sleep(1000 * 3); 
	    } catch (InterruptedException e) {
	        e.printStackTrace();
	    }
	    
	     // main主线程修改子线程的中断状态=true
	     // 子线程检测中断状态=true,则抛出InterruptedException,子线程执行结束
	     thread.interrupt();
	}
}

案例2:子线程等待时,可以通过interrupt()中断子线程

public class Main {
    public static void main(String[] args) throws InterruptedException {
    	System.out.println("主线程:开始执行");
    	
    	// main主线程创建子线程MyThread
    	MyThread t = new MyThread();
        t.start();
        
        Thread.sleep(1000);
        t.interrupt(); // 中断t线程
        t.join(); // 等待t线程结束
        
        System.out.println("主线程:结束执行");
    }
}

class MyThread extends Thread {
    public void run() {
    	System.out.println("MyThread线程:开始执行");
    	
    	// MyThread线程创建子线程HelloThread
    	HelloThread hello = new HelloThread();
        hello.start(); // 启动HelloThread线程
        try {
            hello.join(); // 等待hello线程结束
        } catch (InterruptedException e) {
            System.out.println("MyThread线程:结束执行,interrupted!");
        }
        
        // MyThead线程结束后,中断子线程HelloThread
        hello.interrupt();
    }
}

class HelloThread extends Thread {
    public void run() {
    	System.out.println("Hello线程:开始执行");
        int n = 0;
        while (!isInterrupted()) {
            n++;
            System.out.println(n + " hello!");
        }
        System.out.println("Hello线程:结束执行!");
    }
}

案例3:子线程运行时,可以通过isInterrupted()随时观察子线程的中断状态

public class Main {
	public static void main(String[] args) throws InterruptedException {
		System.out.println("main主线程:开始执行");
        
        // 创建2个子线程
		Thread t1 = new Thread("线程1") {
			@Override
			public void run() {
				System.out.println(getName() + ":开始执行");
				while(!isInterrupted()) {
					System.out.println(UUID.randomUUID());
				}
				System.out.println(getName() + ":结束执行");
			}
		};
		
		Thread t2 = new Thread("线程2") {
			@Override
			public void run() {
				System.out.println(getName() + ":开始执行");
				while(!isInterrupted()) {
					System.out.println((int)(Math.random()*10000));
				}
				System.out.println(getName() + ":结束执行");
			}
		};

        // 启动子线程
		t1.start();
		t2.start();

        // 主线程休眠10毫秒
		Thread.sleep(10);

        // 10毫秒后,中断子线程1
		t1.interrupt();

        // 子线程1执行结束后,继续执行主线程
		t1.join();
		System.out.println("main主线程:结束执行");

        // 主线程执行结束后,中断子线程2
        // 子线程1的中断,不会影响子线程2
		t2.interrupt();
	}
}

4. 线程的让出:yield( )方法

4.1 yield( )方法的作用
  • 线程通过调用yield()方法告诉JVM的线程调度,当前线程愿意让出CPU给其他线程使用。
  • 至于系统是否采纳,取决于JVM的线程调度模型:分时调度模型和抢占式调度模型
    • 分时调度模型:所有的线程轮流获得 cpu的使用权,并且平均分配每个线程占用的 CPU 时间片;
    • 抢占式调度模型:优先让可运行池中优先级高的线程占用 CPU,如果可运行池中的线程优先级相同,那么就随机选择一个线程,使其占用CPU。(JVM虚拟机采用的是抢占式调度模型 )
/**
     * A hint to the scheduler that the current thread is willing to yield
     * its current use of a processor. The scheduler is free to ignore this
     * hint.
     * 向调度程序发出的提示,表示当前线程愿意让出处理器的使用权
     */
    public static native void yield();

案例1:子线程2执行过程中,通过yield()让出CPU,使子线程1执行概率变高。

public static void main(String[] args) {
    // 创建子线程1:打印字母A-Z
    Thread thread1 = new Thread() {
        public void run() {
            for (char c = 'A'; c <= 'Z'; c++) {
                System.out.println(c);
            }
        }
    };

    // 创建子线程2:打印数字65-90
    Thread thread2 = new Thread() {
        public void run() {
            Thread.yield(); // 让当前线程让出CPU
             for (int c = 65; c <= 90; c++) {
                System.out.println(c);
                // Thread.yield(); // 让当前线程让出CPU
            }
        }
    };

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

5. 守护线程(Daemon Thread)

5.1 用户线程与守护线程的区别
  • 用户线程:我们平常创建的普通线程;
  • 守护线程:用来服务于用户线程的线程,在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出;而守护线程执行结束后,虚拟机不会自动退出。
5.2 设置守护线程
  • 在调用start()方法前,调用setDaemon(true)把该线程标记为守护线程
5. 守护线程(Daemon Thread)
5.1 用户线程与守护线程的区别
○
用户线程:我们平常创建的普通线程;
○
守护线程:用来服务于用户线程的线程,在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出;而守护线程执行结束后,虚拟机不会自动退出。
5.2 设置守护线程
○
在调用start()方法前,调用setDaemon(true)把该线程标记为守护线程

案例1:用户线程会影响JVM退出

public class Main {

    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();

        // 创建并启动子线程
        new Thread() {
            @Override
            public void run() {
                //子线程休眠10秒钟
                try {
                    Thread.sleep(10*1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("普通用户线程,运行耗时" + (System.currentTimeMillis() - startTime));
            }
        }.start();

        //主线程休眠3秒,确保在子线程之前结束休眠
        try {
            Thread.sleep(3*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Main主线程,运行耗时 " + (System.currentTimeMillis() - startTime));
    }
}

运行结果分析:普通用户线程,在没有完成打印内容的时候,JVM是不会被结束。

Main主线程,运行耗时 3001
普通用户线程,运行耗时10001

Process finished with exit code 0

案例2:守护线程不会影响JVM退出

public class Main {
    
    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();

        // 创建子线程
        Thread daemonThread = new Thread() {
            @Override
            public void run() {
                //子线程休眠10秒钟
                try {
                    Thread.sleep(10*1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("守护线程,运行耗时" + (System.currentTimeMillis() - startTime));
            }
        };
        daemonThread.setDaemon(true); // 启动线程前,设置子线程为守护线程
        daemonThread.start(); // 启动线程

        //主线程休眠3秒,确保在子线程之前结束休眠
        try {
            Thread.sleep(3*1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Main主线程,运行耗时 " + (System.currentTimeMillis() - startTime));
    }
}

运行结果分析:守护线程,还没有打印出来内容的时候,JVM就已经结束了。

Main主线程,运行耗时 3001

Process finished with exit code 0

案例3:用户线程的中断结束后,主线程的执行结束,会导致JVM的结束退出

public class Main {
	public static void main(String[] args) throws InterruptedException {
		// 守护线程t1
		Thread t1 = new Thread() {
			@Override
			public void run() {
				while(true) {
					System.out.println("守护线程t1 while loop.....");
				}
			}
		};
		t1.setDaemon(true); // 设置守护线程
		t1.start();
		
		// 用户线程t2
		Thread t2 = new Thread() {
			@Override
			public void run() {
				while(!isInterrupted()) {
					System.out.println("用户线程t2 while loop.....");
				}
				System.out.println("用户线程t2线程结束(中断)");
			}
		};
		t2.start();
		
		// 主线程休眠1000毫秒后,中断用户线程t2
		Thread.sleep(1000);
		t2.interrupt(); // 中断用户线程t2
		
		// 主线程执行结束
		System.out.println("main主线程结束。。。。");
		
		// 守护线程自动结束
	}
}

总结

  • 线程的状态有以下6种:New、Runnable、Blocked、Waiting、Timed Waiting、Terminated。
  • join()方法用于实现线程插队,调用完毕后会释放锁。
  • sleep()方法用于实现线程休眠,调用完毕后不会释放锁。
  • interrupt()方法用于设置该线程的中断状态为true。
  • yield()方法用于让出CPU执行。
  • JVM的线程调度模型:分时调度模型和抢占式调度模型。

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

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

相关文章

network-scripts目录下没有ens33文件的问题

作者&#xff1a;程序那点事儿 日期&#xff1a;2023/11/09 06:52 systemctl start NetworkManager #开启网络管理器nmcli con show #查看ens33网卡对应的是ifcfg-Wired_connection_3这个文件&#xff08;网络管理器要开启&#xff0c;不然报错&#xff09;&#xff0c;或者根据…

分布式Redis(14)哈希槽

文章目录 一致性哈希算法理论普通哈希的问题一致性hash算法 Redis 使用哈希槽Redis Cluster集群 为什么Redis是使用哈希槽而不是一致性哈希呢&#xff1f;为什么Redis Cluster哈希槽数量是16384&#xff1f; 关键词&#xff1a;一致性 Hash&#xff0c;哈希槽&#xff0c; 带着…

双指针算法详解

什么是双指针 双指针算法是一种常用的算法策略&#xff0c;通常用于处理有序数组或链表&#xff0c;能够高效地解决许多问题。其核心思想是通过维护两个指针在数组或链表中移动&#xff0c;从而达到减少时间复杂度的目的。我们将通过三个示例代码来深入了解双指针算法的…

《动手学深度学习》笔记2.2——神经网络从基础→进阶 (参数管理-每层的权重/偏置)

目录 0. 前言 正文&#xff1a;参数管理 1. 参数访问 1.1 [目标参数] 1.2 [一次性访问所有参数] 1.3 [从嵌套块收集参数] 2. 参数初始化 2.1 [内置初始化] 2.2 [自定义初始化] 2.3 [参数绑定-共享参数] 3. 小结 4. 练习 0. 前言 课程全部代码&#xff08;pytorch版…

echarts地图的简单使用

echarts地图的简单使用 文章说明核心源码效果展示源码下载 文章说明 主要介绍echarts地图组件的简单使用&#xff0c;记录为文章&#xff0c;供后续查阅使用 目前只是简单的示例&#xff0c;然后还存在着一些小bug&#xff0c;主要是首个Legend的点击会导致颜色全部不展示的问题…

笔试编程-百战成神——Day02

1.简写单词 题目来源&#xff1a; 简写单词——牛客网 测试用例 算法原理 本题的主要难点就是如何识别每一个单词并且返回其首字母大写&#xff0c;最终组成一个新的字符串后输出&#xff0c;这里我们使用while(cin>>str)就可以解决&#xff0c;直接忽略每一个空格直接…

深入理解及如何使用main函数参数

目录 前言&#xff1a;一、main函数参数二、main函数参数的意义及如何使用三、从操作系统层面&#xff08;指令&#xff09;理解main函数参数 前言&#xff1a; 在平时编写代码的过程中&#xff0c;我们会经常写main函数&#xff0c;这是一个程序必不可少的&#xff0c;main 函…

信息汇总(避坑)系统

本系统前期设定为公司避坑系统&#xff0c;在此基础上衍生出公司信息汇总功能 主要功能点&#xff1a;避坑分类、标签、随笔记录、阅读人数、评论&#xff08;用户评论、匿名评论&#xff0c;评论回复等&#xff09;、系统留言&#xff08;支持表情留言&#xff09;、避坑信息…

JavaScript中的无穷大

JavaScript中的无穷大 溢出&#xff1a;overflow,数字结果超过JS表示的数字上限&#xff0c;结果为一个特殊的无穷大Infinity或负无穷大-Infinity. 下溢&#xff1a;underflow是当前结果无限接近于0比JS能表示的最小值还要小&#xff0c;将会返回0&#xff0c;负数下溢就是-0…

剑指offer JZ7 重建二叉树

描述&#xff1a; 给定节点数为 n 的二叉树的前序遍历和中序遍历结果&#xff0c;请重建出该二叉树并返回它的头结点。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}&#xff0c;则重建出如下图所示。 思路&#xff1a; 这道题考察的是二叉树根据先序…

蓝桥杯备赛---引言

我是来自成都锦城学院的2021级学生&#xff0c;第一次参加第十五届蓝桥杯嵌入式赛道获得了国二的名次&#xff0c;接下来将为大家分享各个模块的代码&#xff0c;可以速成省一&#xff0c;但想要取得国一的成绩则需要补偿数据结构、基本c语言函数等相关知识&#xff0c;很遗憾没…

C++ 创建型设计模式

何为设计模式 设计模式是指在软件开发中&#xff0c;经过验证的&#xff0c;用于解决在特定环 境下&#xff0c;重复出现的&#xff0c;特定问题的解决方案&#xff1b; 设计原则 依赖倒置 开放封闭 一个类应该对扩展&#xff08;组合和继承&#xff09;开放&#xff0c;对…

犀牛检测系统源码分享

犀牛检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

N诺计算机考研-错题

B A.LLC,逻辑链路控制子层。一个主机中可能有多个进程在运行,它们可能同时与其他的一些进程(在同一主机或多个主机中)进行通信。因此在一个主机的 LLC子层的一个服务访问点,以便向多个进程提供服务。B.MAC地址,称为物理地址、硬件地址,也称为局域网地址,用来定义网络设…

python与html链接测试

做这个测试我使用了两个资源 1.csdn上收集的参考资料&#xff0c;特此感谢 链接如下&#xff1a;Pycharm社区版创建Flask项目(配置项目文件)_pycharm community flask-CSDN博客 2.kimi 网址如下&#xff1a;Kimi.ai - 帮你看更大的世界 (moonshot.cn) 这是试出来的操作步骤…

python如何查看文件的目录

1、sys.arg[0]: import sys print(sys.argv[0])#当前脚本的位置 输出结果&#xff1a; G:/Pythonxx/test.py 2、os模块 import os print("1111") print (os.getcwd())#获得当前目录 print (os.path.abspath(.))#获得当前工作目录 print (os.path.abspath(..))#获得当…

基于丹摩智算部署可图(Kolors)

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 丹摩智算平台简介一、Kolors 简介介绍技术背景部署与使用前提条件 二、DAMODEL 平台创建适配机器1.1、实例创建 三、服务部署安装 An…

性能测试利器 - Locust框架解析

01 认识Locust 说起性能测试工具&#xff0c;大家肯定想到的都是Jmeter&#xff0c;是的&#xff0c;由于其简单易用、功能强大&#xff0c;已经变成主流的压测工具之一。当需要实现一些高级功能的时候&#xff0c;可以使用Java语言对Jmeter进行扩展。 但是很多小伙伴只会Pyt…

10种数据库技术的发展历程与现状

数据库是互联网的基石&#xff0c;存储着海量信息&#xff0c;使信息可被高效地组织、检索和分享。没有数据库&#xff0c;网站无法记忆用户数据&#xff0c;应用无法提供个性化服务&#xff0c;信息交流将失去智能与连贯性。因此&#xff0c;数据库技术极大地推动了互联网的发…