java二十章多线程

news2024/9/24 19:24:43

概念

有很多工作是可以同时完成的,这种思想放在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();
		
		
	}
 
}

执行结果一样 

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

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

相关文章

PLC:200smart(13-16章)

PLC&#xff1a;200smart 第十三章2、带参子程序3、将子程序设置成库文件 第十三章 项目ValueValue主程序MAIN一个项目只能有一个&#xff0c;循环扫描子程序SBR_0项目中最多有128个&#xff0c;只有在调用时 才执行&#xff08;子程序可以嵌套其他子程序&#xff0c;最多八层…

广州华锐视点:基于VR元宇宙技术开展法律法规常识在线教学,打破地域和时间限制

随着科技的飞速发展&#xff0c;人类社会正逐渐迈向一个全新的时代——元宇宙。元宇宙是一个虚拟的、数字化的世界&#xff0c;它将现实世界与数字世界紧密相连&#xff0c;为人们提供了一个全新的交流、学习和娱乐平台。在这个充满无限可能的元宇宙中&#xff0c;法律知识同样…

构建个人代理池:使用GitHub项目proxy_pool的搭建配置及代码接口详解

手把手教你搭建代理IP池&#xff1a; 项目简介&#xff1a; ​ 爬虫代理IP池项目,主要功能为定时采集网上发布的免费代理验证入库&#xff0c;定时验证入库的代理保证代理的可用性&#xff0c;提供API和CLI两种使用方式。同时你也可以扩展代理源以增加代理池IP的质量和数量。…

分治法之归并排序

思路: 将待排序数组分成两个子数组&#xff0c;计算中间位置mid。对左半部分进行递归排序&#xff0c;得到一个有序的子数组。对右半部分进行递归排序&#xff0c;得到另一个有序的子数组。合并两个有序的子数组&#xff0c;得到一个完整的有序数组。 示例图: 代码: #include&…

WPF绘制进度条(弧形,圆形,异形)

前言 WPF里面圆形进度条实现还比较麻烦,主要涉及到的就是动态绘制进度条的进度需要用到简单的数学算法。其实原理比较简单,我们需要的是话两条重叠的弧线,里面的弧线要比里面的弧线要宽,这样简单的雏形就出来了。 基础写法 我们可以用Path来绘制弧线,代码如下: <Gr…

Linux:服务器管理工具宝塔(bt)安装教程

一、简介 bt宝塔Linux面板是提升运维效率的服务器管理软件&#xff0c;支持一键LAMP/LNMP/集群/监控/网站/FTP/数据库/JAVA等多项服务的管理功能 二、安装 使用 SSH 连接工具&#xff0c;如堡塔SSH终端连接到您的 Linux 服务器后&#xff0c;挂载磁盘&#xff0c;根据系统执…

C++基础——文件操作

文章目录 1 概述2 文本文件2.1 写文件2.1.1 写文件流程2.1.2 文件打开方式 2.2 读文件 3 二进制文件3.1 写文件3.2 读文件 1 概述 程序最基本的操作之一就是文件操作&#xff0c;程序运行时的数据都是临时数据&#xff0c;当程序结束后就不复存在了。通常都是通过文件或其他持…

酷狗音乐app 评论signature

文章目录 声明目标加密参数定位翻页逻辑代码实现 声明 本文章中所有内容仅供学习交流&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff0c;若有侵权&#xff0c;请私信我立即删除&#xff01; 目标 复制curl转python # -*- c…

SQL 数据操作技巧:SELECT INTO、INSERT INTO SELECT 和 CASE 语句详解

SQL SELECT INTO 语句 SELECT INTO 语句将数据从一个表复制到一个新表中。 SELECT INTO 语法 将所有列复制到新表中&#xff1a; SELECT * INTO newtable [IN externaldb] FROM oldtable WHERE condition;只复制一些列到新表中&#xff1a; SELECT column1, column2, colu…

MySQL三大日志详细总结(redo log undo log binlog)

MySQL日志 包括事务日志&#xff08;redolog undolog&#xff09;慢查询日志&#xff0c;通用查询日志&#xff0c;二进制日志&#xff08;binlog&#xff09; 最为重要的就是binlog&#xff08;归档日志&#xff09;事务日志redolog&#xff08;重做日志&#xff09;undolog…

数据结构(超详细讲解!!)第二十六节 图(上)

1.基本概念 图&#xff08;Graph&#xff09;是一种较线性表和树更为复杂的非线性结构。是对结点的前趋和后继个数不加限制的数据结构&#xff0c;用来描述元素之间“多对多”的关系(即结点之间的关系是任意的)。 一个图G &#xff08;V&#xff0c;E&#xff09;由顶点&…

从谷歌搜索结果出现 AI 生成的图片谈起:AI的利与弊

随着人工智能&#xff08;AI&#xff09;的不断发展&#xff0c;其应用领域也越来越广泛。谷歌搜索是现代人日常生活中的一个常用工具&#xff0c;经常用于获取各种信息。最近&#xff0c;谷歌搜索结果中甚至出现了由AI生成的图片&#xff0c;这引发了人们对AI技术的讨论。 首…

CentOS7搭建Kubernetes集群

环境准备&#xff1a;配置好静态IP地址的Centos7&#xff08;2核、master内存3GB、slave内存2GB&#xff09;。 搭建概述&#xff1a;先将一台虚拟机搭建为master、随后克隆出两台虚拟机作为从节点。 虚拟机主机名和IP地址&#xff1a; 主机名IP地址master192.168.138.110sl…

vue3高德地图使用,地址搜索,地址逆解析

在vue3项目里使用高德地图 高德地图文档 先在项目的index.html页面里添加一些东西 <script type"text/javascript">window._AMapSecurityConfig {securityJsCode: "xxxxxxxxxxxxx", //高德安全码};</script> <script src"https://…

Ubuntu Server 20.04.6安装Anaconda3

下载安装包 去下面的网页找到自己想要安装的对应版本的链接&#xff1a; https://repo.anaconda.com/archive/ 我安装的版本链接如下&#xff1a; https://repo.anaconda.com/archive/Anaconda3-2023.09-0-Linux-x86_64.sh 复制这个链接后使用如下命令下载&#xff1a; wget …

外汇天眼:在QOINTEC投资需缴纳分成费才给出金?这合理么?

一般来说&#xff0c;在正规的平台上申请出金是不需要缴纳什么费用的&#xff0c;除非有一些特殊情况&#xff0c;像低额出金、没有交易就申请出金等情况下&#xff0c;或许会让你缴纳一定的手续费或者隔夜利息费等&#xff08;不同的平台有不同的规则&#xff09;&#xff0c;…

python爬取robomaster论坛数据,作为后端数据

一. 内容简介 python爬取robomaster论坛数据&#xff0c;作为后端数据 二. 软件环境 2.1vsCode 2.2Anaconda version: conda 22.9.0 2.3代码 三.主要流程 3.1 接口分析 # 接口分析 # 全部数据 # https://bbs.robomaster.com/forum.php?modforumdisplay&fid63 2…

LLM 分布式训练框架 | DeepSpeed与Accelerate

&#x1f680; 简单记录下根据网上资料&#xff08;如Reference中所列&#xff09;所学到的一些知识&#xff0c;这里主要介绍的是deepspeed分布式训练框架相关概念。 &#x1f604;小日记&#xff1a;今天太舒服了&#xff0c;早上跑了6km&#xff0c;晚上吃了养生菌菇火锅~ …

分布编译和注释

文章目录 分布编译预处理编译汇编链接 注释单行注释多行注释预处理注释 总结 分布编译 上一节使用 gcc main.c就生成了a.exe的可执行文件&#xff0c;提到了将main.c文件生成a.exe实际上执行了以下四步&#xff1a; 预处理编译汇编链接   每一步都有单独的指令&#xff0c;而…

C++学习之继承中修改成员权限细节

看看下面的代码 这是错误的 class A { public:int x 10; }; class B :public A {using A::x;int x 100; };看看函数 class A { public:void fun(){cout << "uuuu" << endl;} }; class B :public A { public:using A::fun;void fun(){cout << …