java二十章多线程

概念

有很多工作是可以同时完成的,这种思想放在Java中被称为并发,并发完成每一件事被称为线程。

程序员可以在程序中执行多个线程,每一个线程完成一个功能//与其他线程并发执行,这种机制被称为多线程,并不算所有编程语言都支持多线程。

创建线程

继承Thread类和实现Runnable接口两种方法

继承Thread类

是Java.long包下的一个类,在这个类中实例化对象代表线程,程序员启动一个新线程需要建立一个实例。Thread类常用的两种构造方法如下:

public Thread():创建一个新的线程对象

public Thread(String threadName):创建一个名为threadName的线程对象

继承Thread类创建一个新的线程的语法如下:

public class ThreadTest extends Thread{
}

完成线程真实代码的功能放在run()方法,当继承Thread类后,就可以在该线程中覆盖run()方法,将实现线程功能的代码写入run()方法中,调用run()方法。

Thread对象需要一个任务来执行,任务是指线程在启动时执行的工作,这个代码写在了run()方法中,语法格式如下:

public void run(){

如果start()方法调用一个已经启动的线程,系统将抛出IllegalThreadStateException异常

例题20.1
 

package lx;
 
public class Demo20_1 extends Thread {
	public void run(){
		for(int i=0;i<=10;i++) {
			System.out.println(i+"");
		}
	}
	public static void main(String[] args) {
		Demo20_1 th=new Demo20_1();
		th.start();
		
	}
 
}
 

 

实现Runnable接口

线程都是通过扩展 Thread 类来创建的,如果需要继承其他类(非 Thread类),而且还要使当前类实现多线程,那么可以通过 Runnable 接口来实现。实现 Runnable 接口的语法如下:

public class Thread extends Object implements Runnable{
}

 实质上 Thread 类实现了 Runnable 接口,其中的run()方法正是对 Runnable 接口中的 run()方法的具体实现

实现 Runnable 接口的程序会创建一个 Thread 对象,并将 Runnable 对象与 Thread 对象相关联。

Thread 类中有两个构造方法:

public Thread(Runnable target)。

public Thread(Runnable target,String name)。

 这两个构造方法的参数中都存在 Runnable 实例

使用 Runnable 接口启动新的线程的步骤如下:

建立 Runnable 对象。

使用参数为 Runnable 对象的构造方法创建 Thread 实例。

调用 start()方法启动线程。

 

 线程最引人注目的部分应该是与 Swing 相结合创建GUI程序

例题20.2
 

package lx;
 
import java.awt.Container;
 
import javax.swing.JFrame;
import javax.swing.*;
 
public class Demo20_2 extends JFrame {
	int c=0;//图标横坐标
	public Demo20_2() {
		setBounds(300,200,250,100);//绝对定位窗体大小和位置
		Container con=getContentPane();//主容器
		con.setLayout(null);//使窗体不使用任何布局管理器
		
		Icon img=new ImageIcon("src/1.gif");//图标对象
		JLabel jl=new JLabel(img);//显示图标的标签
		jl.setBounds(10, 10, 200, 50);//设置标签的位置和大小
		Thread t=new Thread() {//定义匿名线程对象
			public void run() {
				while(true) {
					jl.setBounds(c, 10, 200, 50);//将标签的横坐标用线程表示
					try {
						Thread.sleep(500);//使线程休眠500毫秒
					}catch(InterruptedException e) {
						e.printStackTrace();
					}
					c+=4;//使横坐标每次增加4
					if(c>=120) {
						c=10;//当图标到达标签最右边时,使其回到标签最左边
					}
				}
			}
		};
		t.start();//启动线程
		con.add(jl);//将标签添加到容器中
		setVisible(true);//使窗体可见
		setDefaultCloseOperation(EXIT_ON_CLOSE);//设置窗体的关闭方式
	}
	public static void main(String[] args) {
		new Demo20_2();
	}
 
}

为了使图标具有滚动功能,需要在类的构造方法中创建 Thread 实例。

在创建该实例的同时需要 Runnable 对象作为 Thread 类构造方法的参数,然后使用内部类形式实现 run()方法。

在 run()方法中主要循环图标的横坐标位置,

当图标横坐标到达标签的最右方时,再次将图标的横坐标置于图标滚动的初始位置。

启动一个新的线程,不是直接调用 Thread 子类对象的 run()方法,而是调用 Thread 子类的 start()方法,Thread 类的 start()方法产生一个新的线程,该线程运行 Thread 子类的 run()方法。

线程的生命周期 

线程具有生命周期,其中包含 7 种状态,分别为出生状态、就绪状态、运行状态、等待状态、休眠状态、阻塞状态和死亡状态。

出生状态就是线程被创建时处于的状态,在用户使用该线程实例调用start()方法之前线程都处于出生状态.

当用户调用 start()方法后,线程处于就绪状态 

当线程得到系统资源后就进入运行状态。

旦线程进入可执行状态,它会在就绪与运行状态下转换,同时也有可能进入等待、休眠、阻塞或死亡状态。

虽然多线程看起来像同时执行,但事实上在同一时间点上只有一个线程被执行,只是线程之间切换较快,所以才会使人产生线程是同时进行的假象。

操作线程的方法

操作线程有很多方法,这些方法可以使线程从某一种状态过波到另一种状态。

 线程的休眠

一种能控制线程行为的方法是调用 seep()方法,sleep()方法需要一个参数用于指定该线程休眠的时间,该时间以毫秒为单位。slep()方法的语法如下:

try{
Thread.sleep(2000);

}catch(InterruptedException e){
e.printStackTrace();

}

上述代码会使线程在 2 秒之内不会进入就绪状态。

由于 sleep()方法的执行有可能抛InterrupledException 异常,所以将 sleep()方法的调用放在 try-catch 块中。

不能保证线程醒来后进入运行状态,只能保证它进入就绪状态。

例题20.3

package lx;
 
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
 
import javax.swing.JFrame;
 
public class Demo20_3 extends JFrame {
	private static Color[]color= {//定义颜色数组
			Color.BLACK,Color.BLUE,Color.CYAN,Color.GREEN,Color.ORANGE,Color.YELLOW
			,Color.RED,Color.PINK,Color.LIGHT_GRAY
	};
	private static  final Random rand=new Random();
	//创建随机对象
	private static Color getC() {//获取随机颜色值的方法
		return color[rand.nextInt(color.length)];
	}
	public Demo20_3() {
		Thread t=new Thread(new Runnable() {
			//创建匿名线程对象
			int x=70;
			//定义初始坐标
			int y=50;
			public void run() {
				while(true) {//无限循环
					try {
						Thread.sleep(100);//线程休眠0.1秒
				}catch(InterruptedException e){
					e.printStackTrace();
				}
				Graphics g= getGraphics();//获取组件绘图上下文对象
				g.setColor(getC());//设置绘图颜色
				g.drawLine(x, y, 200, y++);//绘制直线并递增垂直坐标
				if(y>=100) {
					y=50;
				}
			}
		}
			});
		t.start();//启动线程
	}
	
	public static void main(String[] args) {
		init(new Demo20_3(),300,100);
	}
	
	public static void init(JFrame f,int w,int h) {//初始化程序界面的方法
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setSize(w, h);
		f.setVisible(true);
	}
}

在本实例中定义了 getC()方法,该方法用于随机产生 Color 类型的对象并且在产生线程的匿名内部类中使用 getGraphics()方法获取 Graphics 对象,使用该对象调用 setColor()方法为图形设置颜色。调用 drawLine()方法绘制一条线段,同时线段会根据纵坐标的变化自动调整。

线程的加入

如果当前某程序为多线程程序,假如存在一个线程 A,现在需要插入线程 B,并要求线程 B 先执行完毕,然后再继续执行线程 A,此时可以使用 Thread 类中的 join()方法来完成。

例题20.4
 

package lx;
 
import java.awt.BorderLayout;
 
import javax.swing.*;
 
public class Demo20_4 extends JFrame{
	private Thread A;//定义两个线程
	private Thread B;
	private JProgressBar Bar=new JProgressBar();//定义两个进度条组件
	private JProgressBar Bar2=new JProgressBar();
	
	public static void main(String[] args) {
		Demo20_4 Text=new Demo20_4();
		Text.setVisible(true);
 
	}
	public Demo20_4() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(200,200,200,100);
		getContentPane().add(Bar,BorderLayout.NORTH);//将进度条设置在窗体最北面
		getContentPane().add(Bar2,BorderLayout.SOUTH);//将进度条设置在窗体最南面
		Bar.setStringPainted(true);//设置进度条显示数字字符
		Bar2.setStringPainted(true);
		A=new Thread(new Runnable() {//使用匿名内部类形式初始化Thread实例
			int c=0;
			public void run() {//重写润()方法
				while(true) {
					Bar.setValue(c++);//设置进度条当前值
					try {
						
						Thread.sleep(100);//让A线程休眠100毫秒
						
						B.join();//让/B调用join()方法
						if(c==30)//设置当A线程走到了30,B线程才启动
							B.start();//启动B线程
					}catch(InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		});
		A.start();//启动A线程
		B=new Thread(new Runnable() {
			int c=0;
			public void run() {
				while(true) {
					Bar2.setValue(++c);//设置进度条当前值
					try {
						Thread.sleep(100);//让B线程休眠100毫秒
						
					}catch(InterruptedException e) {
						e.printStackTrace();
						
				}
					if(c==100)//当c变量增长为100时
						break;			//跳出循环	
				}
			}
		});
		
		}
	}

 

线程的中断

如果线程是因为使用了 sleep()或 wait()方法进入了就绪状态,可以使用 Thread 类中 interrupt()方法使线程离开run()方法,同时结束线程,但程序会抛出 InterruptedException 异常,用户可以在处理该异常时完成线程的中断业务处理,如终止 while 循环。

例题20.5
 

package lx;
 
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
 
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
 
public class Demo20_5 extends JFrame{
	
	public Demo20_5(){
		JProgressBar Bar=new JProgressBar();//创建进度条
		getContentPane().add(Bar,BorderLayout.NORTH);//将进度条设置在窗体最北面
		JButton b=new JButton("停止");
		getContentPane().add(b,BorderLayout.SOUTH);//将进度条设置在窗体最南面
		Bar.setStringPainted(true);//设置进度条显示数字字符
		Thread t=new Thread(new Runnable() {
			int c=0;
			public void run() {
				while(true) {
					Bar.setValue(++c);//设置进度条当前值
					try {
						Thread.sleep(100);//让A线程休眠100毫秒
					}catch(InterruptedException e) {//捕捉InterruptedException异常
						System.out.println("当前线程程序被中断");
						break;
					}
				}
			}
			
		});
		b.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				t.interrupt();//中断线程
			}
		});
		t.start();//启动线程
	}
	public static void init(JFrame frame,int w,int h) {
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(w, h);
		frame.setVisible(true);
	}
	public static void main(String[] args) {
		init(new Demo20_5(),100,100);
 
	}
 
}

 

 

线程的礼让

Thread 类中提供了一种礼让方法,使用 yield()方法表示,它只是给当前正处于运行状态的线程一个提醒,告知它可以将资源礼让给其他线程,但这仅是一种暗示,没有任何一种机制保证当前线程会将资源礼让。yicld()方法使具有同样优先级的线程有进入可执行状态的机会,在当前线程放弃执行权时会再度回到就绪状态。

线程的优先级

每个线程都具有各自的优先级,线程的优先级可以表明在程序中该线程的重要性。

线程的优先级可以使用 setPriority()方法调整,如果使用该方法设置的优先级不在 1~10,将产生IllegalArgumentException 异常。

例题20.6
 

package lx;
 
public class Demo20_6 implements Runnable{
	String name;
	public 	Demo20_6(String name) {
		this.name=name;
	}
		public void run() {
			String tmp="";
			for(int i=0;i<50000;i++) {//完成5万次字符串拼接
				tmp+=i;
			}
			System.out.println(name+"线程完成任务");
		}
	
	
	public static void main(String[] args) {
	Thread a=new Thread(new Demo20_6("A"));//A线程优先级最小
	a.setPriority(1);
	Thread b=new Thread(new Demo20_6("B"));
	b.setPriority(3);
	Thread c=new Thread(new Demo20_6("C"));
	c.setPriority(7);
	Thread d=new Thread(new Demo20_6("D"));//D线程优先级最大
	d.setPriority(10);
	a.start();
	b.start();
	c.start();
	d.start();
	//线程的执行顺序由CPU决定,所有可能不一定按优先级排序
	}
 
}

 

由于线程的执行顺序是由 CPU 决定的,即使线程设定了优先级也是作为 CPU 的参考数据,所以真实的运行结果可能并不一定按照优先级排序

线程同步

在单线程程序中,每次只能做一件事情,后面的事情需要等待前面的事情完成后才可以进行,但是如果使用多线程程序,就会发生两个线程抢占资源的问题,如两个人同时说话、两个人同时过同-个独木桥等。所以,在多线程编程中需要防止这些资源访问的冲突。Java 提供了线程同步的机制来防止资源访问的冲突。

 线程安全

实际开发中,使用多线程程序的情况很多,以火车站售票系统为例,在代码中判断当前票数是否大于 0,如果大于 0 则执行将该票出售给乘客的功能,但当两个线程同时访问这段代码时(假如这时只剩下一张票),第一个线程将票售出,与此同时第二个线程也已经执行完成判断是否有票的操作,并得出票数大于 0 的结论,于是它也执行售出操作,这样就会产生负数。

所以,在编写多线程程序时,应该考虑到线程安全问题。实质上线程安全问题来源于两个线程同时存取单一对象的数据。

实例

package lx;
 
public class Demo20_6_1 implements Runnable {
	int n=10;//设置当前总票数
	public void run() {
		while(true) {//设置无限循环
			if(n>0) {//判断当前票数是否大于 0
				try {
					Thread.sleep(100);		//使当前线程休眠 100毫秒	
					}
			catch(InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"————票数"+n--);//票数减1
			}	
		}
	}
	
	
	public static void main(String[] args) {
		Demo20_6_1 t=new Demo20_6_1();//实例化类对象
		Thread tA=new Thread(t,"线程一");//以该类对象分别实例化 4 个线程
		Thread tB=new Thread(t,"线程二");
		Thread tC=new Thread(t,"线程三");
		Thread tD=new Thread(t,"线程四");
		tA.start();//分别启动线程
		tB.start();
		tC.start();
		tD.start();
		
		
	}
 
}

 

线程同步机制

该如何解决资源共享的问题呢? 所有解决多线程资源冲突问题的方法基本上都是采用给定时间只允许一个线程访问共享资源的方法,这时就需要给共享资源上一道锁。

同块步

Java 中提供了同步机制,可以有效地防止资源冲突。同步机制使用 synchronized 关键字,使用该关键字包含的代码块称为同步块,也称为临界区,语法如下:

synchronized (Object){
}

 通常将共享资源的操作放置在 synchronized 定义的区域内,这样当其他线程获取到这个锁时,就必须等待锁被释放后才可以进入该区域。

例题20.7

package lx;
 
public class Demo20_6_1 implements Runnable {
	int n=10;//设置当前总票数
	public void run() {
		while(true) {//设置无限循环
			synchronized (this) {
				if(n>0) {//判断当前票数是否大于 0
					try {
						Thread.sleep(100);		//使当前线程休眠 100毫秒	
						}
				catch(InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"————票数"+n--);//票数减1
				}	
			}
			
		}
	}
	
	
	public static void main(String[] args) {
		Demo20_6_1 t=new Demo20_6_1();//实例化类对象
		Thread tA=new Thread(t,"线程一");//以该类对象分别实例化 4 个线程
		Thread tB=new Thread(t,"线程二");
		Thread tC=new Thread(t,"线程三");
		Thread tD=new Thread(t,"线程四");
		tA.start();//分别启动线程
		tB.start();
		tC.start();
		tD.start();
		
		
	}
 
}

 

从这个结果可以看出,打印到最后票数没有出现负数,这是因为将共享资源放置在了同步块中,不管程序如何运行都不会出现负数。

同步方法

同步方法就是在方法前面用 synchronized 关键字修饰的方法,其语法如下:

synchronized void f(){
}

 当某个对象调用了同步方法时,该对象上的其他同步方法必须等待该同步方法执行完毕后才能被执行。必须将每个能访问共享资源的方法修饰为 synchronized,否则就会出错。

修改20.7的代码如下:

package lx;
 
public class Demo20_6_1 implements Runnable {
	int n=10;//设置当前总票数
	
	public  synchronized void du() {
		if(n>0) {//判断当前票数是否大于 0
			try {
				Thread.sleep(100);		//使当前线程休眠 100毫秒	
				}
		catch(InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"————票数"+n--);//票数减1
		}	
	}
	public void run() {
		while(true) {//设置无限循环
			du();
			
		}
	}
	
	
	public static void main(String[] args) {
		Demo20_6_1 t=new Demo20_6_1();//实例化类对象
		Thread tA=new Thread(t,"线程一");//以该类对象分别实例化 4 个线程
		Thread tB=new Thread(t,"线程二");
		Thread tC=new Thread(t,"线程三");
		Thread tD=new Thread(t,"线程四");
		tA.start();//分别启动线程
		tB.start();
		tC.start();
		tD.start();
		
		
	}
 
}

执行结果一样 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何提高3D建模技能?

无论是制作影视动画还是视频游戏&#xff0c;提高3D建模技能对于你的工作都至关重要的。那么如何能创建出精美的3D模型呢&#xff1f;本文给大家一些3D建模技能方面的建议。 3D建模通过专门的软件完成&#xff0c;涉及制作三维对象。这项技能在视频游戏开发、建筑、动画和产品…

FFmpeg架构全面分析

一、简介 它的官网为&#xff1a;https://ffmpeg.org/&#xff0c;由Fabrice Bellard&#xff08;法国著名程序员Born in 1972&#xff09;于2000年发起创建的开源项目。该人是个牛人&#xff0c;在很多领域都有很大的贡献。 FFmpeg是多媒体领域的万能工具。只要涉及音视频领…

【Vulnhub 靶场】【DriftingBlues: 9 (final)】【简单】【20210509】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/driftingblues-9-final,695/ 靶场下载&#xff1a;https://download.vulnhub.com/driftingblues/driftingblues9.ova 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年05月09日 文件大小&#xff1a;738 …

达索系统SOLIDWORKS 2024工程图新功能

工程图概述 设计模型不仅能比绘制直线更快&#xff1b;SOLIDWORKS 从模型中生成工程图&#xff0c;模型的参数和几何关系在工程图中被保留&#xff0c;这样工程图可反映模型的设计意图&#xff1b;模型或工程图中的更改反映在其相关文件中&#xff0c;这样更改起来更容易&…

map文件解析

Map文件内容分为以下五段&#xff1a; 1&#xff09;Section Cross References&#xff1a;模块、段(入口)交叉引用&#xff1b;(ASR编译生成的map文件没有输出该段信息) 2&#xff09;Removing Unused input sections from the image&#xff1a;移除未使用的模块&#xff1…

【Linux】基础IO--文件基础知识/文件操作/文件描述符

文章目录 一、文件相关基础知识二、文件操作1.C语言文件操作2.操作系统文件操作2.1 比特位传递选项2.2 文件相关系统调用2.3 文件操作接口的使用 三、文件描述符fd1.什么是文件描述符2.文件描述符的分配规则 一、文件相关基础知识 我们对文件有如下的认识&#xff1a; 1.文件 …

java设计模式学习之【建造者模式】

文章目录 引言建造者模式简介定义与用途实现方式&#xff1a; 使用场景优势与劣势建造者模式在spring中的应用CD&#xff08;光盘&#xff09;的模拟示例UML 订单系统的模拟示例UML 代码地址 引言 建造者模式在创建复杂对象时展现出其强大的能力&#xff0c;特别是当这些对象需…

带大家做一个,易上手的家常炒鸡蛋

想做这道菜 先准备五个鸡蛋 然后将鸡蛋打到碗里面 然后 加小半勺盐 这个看个人喜好 放多少都没问题 不要太咸就好 将鸡蛋搅拌均匀 起锅烧油 油温热了之后 放三个干辣椒进去炒 干辣椒烧黑后 捞出来 味道就留在油里了 然后 倒入鸡蛋液 翻炒 注意翻炒 不要粘锅底 或者 一面糊…

嵌入式Linux:ARM驱动+QT应用+OpenCV人脸识别项目实现

一、前言&#xff1a; 这个项目主要分为两部分&#xff0c;客户端&#xff08;ARM板端&#xff09;负责利用OpenCV采集人脸数据&#xff0c;利用TCP将人脸数据发送给服务器&#xff0c;然后服务器根据人脸数据进行人脸识别&#xff0c;将识别后的结果返还给客户端&#xff0c;客…

【Linux】环境变量

文章目录 1. 环境变量的概念2. 常见的环境变量3. 查看环境变量的方法4. 测试PATH5. 和环境变量有关的命令6. 环境变量的组织方式7. 通过代码获取环境变量7.1 通过命令行的第三个参数7.2 通过第三方变量environ 8. 通过系统调用获取9. 环境变量的全局属性 1. 环境变量的概念 **…

函数指针数组指针数组传参的本质字符指针(进阶篇)

&#x1f680; 作者&#xff1a;阿辉不一般 &#x1f680; 你说呢&#xff1a;不服输的你&#xff0c;他们拿什么赢 &#x1f680; 专栏&#xff1a;爱上C语言 &#x1f680;作图工具&#xff1a;draw.io(免费开源的作图网站) 如果觉得文章对你有帮助的话&#xff0c;还请点赞…

【带头学C++】----- 八、C++面向对象编程 ---- 8.5 struct结构体类型增强使用说明

目录 8.5 struct结构体类型增强使用说明 8.5.1 C结构体可以定义成员函数 8.5.2 c中定义结构体变量可以不加struct关键字 8.6 bool布尔类型关键字 8.5 struct结构体类型增强使用说明 第六章对结构体的使用、内存对齐以及数组、深拷贝和浅拷贝进行了一个详细的说明&#xff0c…

带键扫的LED专用驱动方案

一、基本概述 TM1650 是一种带键盘扫描接口的LED&#xff08;发光二极管显示器&#xff09;驱动控制专用电路。内部集成有MCU输入输出控制数字接口、数据锁存器、LED 驱动、键盘扫描、辉度调节等电路。TM1650 性能稳定、质量可靠、抗干扰能力强&#xff0c;可适用于24 小时长期…

对抗产品团队中的认知偏误:给产品经理的专家建议

今天的产品经理面临着独特的挑战。他们不仅需要设计和构建创新功能&#xff0c;还必须了解这些功能将如何为客户带来价值并推进关键业务目标。如果不加以控制&#xff0c;认知偏差可能会导致您构建的内容与客户想要的内容或业务需求之间不一致。本文将详细阐述产品经理可以避免…

【EI会议征稿】第四届应用数学、建模与智能计算国际学术会议(CAMMIC 2024)

第四届应用数学、建模与智能计算国际学术会议&#xff08;CAMMIC 2024&#xff09; 2024 4th International Conference on Applied Mathematics, Modelling and Intelligent Computing 第四届应用数学、建模与智能计算国际学术会议&#xff08;CAMMIC 2024&#xff09;将于…

超详细!Opencv人脸识别!附源码!

一、新建环境 注意&#xff01;&#xff01;确定后需要关闭项目&#xff0c;重新打开&#xff0c;终端的环境才会变化&#xff01;&#xff01; 二、下载安装包&#xff08;只需要3个即可&#xff09; 1. 下载dlib包 pip install dlib-19.19.0-cp38-cp38-win_amd64.whl.whl …

XTU OJ 1339 Interprime 学习笔记

链接 传送门 代码 #include<bits/stdc.h> using namespace std;const int N1e610; //78498 我计算了一下&#xff0c;6个0的范围内有这么多个素数&#xff0c;所以开这么大的数组存素数 //计算的代码是一个循环 int prime[80000]; int a[N],s[N];//s数组是前缀和数组b…

力扣 --- 删除有序数组中的重复项 II

题目描述&#xff1a; 给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的…

时序预测 | Python实现GA-TCN-LSTM遗传算法-时间卷积神经网络-长短期记忆网络时间序列预测

时序预测 | Python实现GA-TCN-LSTM遗传算法-时间卷积神经网络-长短期记忆网络时间序列预测 目录 时序预测 | Python实现GA-TCN-LSTM遗传算法-时间卷积神经网络-长短期记忆网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 使用先进的机器学习技术和优化算法…

Ubuntu systemd-analyze命令(系统启动性能分析工具:分析系统启动时间,找出可能导致启动缓慢的原因)

文章目录 Ubuntu systemd-analyze命令剖析目录简介systemd与systemd-analyze工作原理 安装和使用命令参数详解用例与示例显示启动时间&#xff08;systemd-analyze time&#xff09;列出启动过程中各个服务的启动时间&#xff08;systemd-analyze blame&#xff09;显示系统启动…