包装类、多线程的基本使用

包装类

1.基本数据类型对应的引用数据类型(包装类)

1.概述:所谓的包装类就是基本类型对应的类(引用类型),我们需要将基本类型转成包装类,从而让基本类型具有类的特性(说白了,就是将基本类型的数据转成包装类,就可以使用包装类中的方法来操作此数据)2.为啥要学包装类:a.将来有一些特定操作,调用方法需要传递包装类比如:ArrayList集合,add(Object obj),我们只能传递Object的子类对象,此时如果我们想传递一些基本类型的数据,Object作为一个引用类型不能直接接受基本类型,所以我们需要先将基本类型转成包装类传递到Object3.将来我们需要让基本类型和包装类互相转换,为啥:a.基本类型为啥转成包装类:调用某个方法,方法参数传递Object类型,ArrayList集合,add(Object obj),我们只能传递Object的子类对象,此时如果我们想传递一些基本类型的数据,Object作为一个引用类型不能直接接受基本类型,所以我们需要先将基本类型转成包装类传递到Object中b.包装类为啥转成基本类型:包装类不能直接使用+ - * /做运算,所以需要先将包装类转成基本类型,才能直接使用+ - * /符号
基本类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

2.Inteaer的介绍以及应用

2.1Integer基本使用

1.概述:Integerint的包装类
2.构造:a.Integer(String i):i必须是数字格式b.Integer(int i)    
public class Exercise {public static void main(String[] args) {Integer integer = new Integer("10");System.out.println("integer = " + integer);Integer integer1 = new Integer(100);System.out.println("integer1 = " + integer1);Boolean aBoolean = new Boolean(true);System.out.println("aBoolean = " + aBoolean);Boolean aBoolean1 = new Boolean("true");System.out.println("aBoolean1 = " + aBoolean1);Boolean aBoolean2 = new Boolean("True");System.out.println("aBoolean2 = " + aBoolean2);}
}
//输出
integer = 10
integer1 = 100
aBoolean = true
aBoolean1 = true
aBoolean2 = true
Boolean aBoolean = new Boolean(true);

Boolean包装类中 , 底层调用了parseBoolean(String s) , 在parseBoolean中调用了equals.IgnoreCase(s) , 忽略了大小写

public static boolean parseBoolean(String s) {return "true".equalsIgnoreCase(s);
}

2.2装箱and拆箱

1.装箱:将基本类型变成包装类2.方法:static Integer valueOf(int i)  static Integer valueOf(String s) -> s需要是数字格式
1.拆箱:将包装类转成基本类型
2.方法:int intValue()  
public class Exercise03 {public static void main(String[] args) {//装箱Integer integer = Integer.valueOf(10);System.out.println("integer = " + integer);Integer integer1 = Integer.valueOf("15");System.out.println("integer1 = " + integer1);//拆箱int value = integer.intValue();System.out.println("value = " + value);int value1 = integer1.intValue();System.out.println("value1 = " + value1);}
}

2.3自动拆箱装箱

在操作的过程中,基本类型和包装类之间可以自动转换

public class Demo04Integer {public static void main(String[] args) {Integer i = 10;i+=1;System.out.println(i);}
}

反编译后如下图:

1694497269393

笔试题:

public class Demo05Integer {
public static void main(String[] args) {Integer i1 = 100;Integer i2 = 100;System.out.println(i1==i2);//trueInteger i3 = 127;Integer i4 = 127;System.out.println(i3==i4);//trueInteger i5 = 128;Integer i6 = 128;System.out.println(i5==i6);//false
}
}
包装类缓存对象
Byte-128-127
Short-128-127
Integer-128-127
Long-128-127
Float没有
Double没有
Character0-127
Booleantrue和false

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

@IntrinsicCandidate
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);
}

可以发现当数值超过了128就会开辟一个新空间 , 即new Integer(i)

此为享元设计模式

3.基本类型与String转换

3.1 基本类型往String转

1.方式1:+
2.方式2:String中的静态方法static String valueOf(int i)  
public class String_transform {public static void main(String[] args) {//基本数据类型转包装类//方式1: static String valueOf(int a)String s = String.valueOf(10);System.out.println(s+1);//方式2:+""int i  = 10;String s1 = i+"";System.out.println(s1+1);}
}

3.2 String转成基本数据类型

每一个包装类中都有一个parseXXX的方法
位置方法说明
Bytestatic byte parseByte(String s)将字符串转成byte
Shortstatic short parseShort(String s)将字符串转成short
Integerstatic int parseInt(String s)将字符串转成int
Longstatic long parseLong(String s)将字符串转成long
Floatstatic float parseFloat(String s)将字符串转成float
Doublestatic double parseDouble(String s)将字符串转成double
Booleanstatic boolean parseBoolean(String s)将字符串转成boolean
public class String_transform {public static void main(String[] args) {//基本数据类型转包装类//方式1: static String valueOf(int a)String s = String.valueOf(10);System.out.println(s+1);//方式2:+""int i  = 10;String s1 = i+"";System.out.println(s1+1);//将String转为基本数据类型int i1 = Integer.parseInt("101");System.out.println("i1+1 = " + i1+1);double parseDouble = Double.parseDouble("10.2");System.out.println("parseDouble+1 = " + parseDouble + 1);}
}

将来开发,我们定义javabean的时候,需要将基本类型的字段(成员变量)定义成包装类类型的

1.将来我们的javabean都是和表对应的
2.针对下面的Student,创建出来的表
id   -> 一般作为表的主键使用,而且主键会自增
name
age如果主键为自增,我们添加数据时sql语句可以这么写:
insert into student (id,name,age) values (NULL,'柳岩',36);
我们可以用NULL占位(主键自增的列)而我们将来需要将javabean对象中的数据添加到sql语句中,从而保存到数据库中包装类型的属性默认值为NULL,所以到时候我们将javabean对象中的数据放到数据库中时,我们不需要单独为id属性赋值如果不给javabean中的id赋值: Student s = new Student(null,"哈哈",36)
此时我们将javabean中的属性值获取出来放到sql中,正好是: 
insert into student (id,name,age) values (NULL,'哈哈',36);
public class User {private Integer uid;private String name;private Integer age;public User(Integer uid, String name, Integer age) {this.uid = uid;this.name = name;this.age = age;}public User() {}public Integer getUid() {return uid;}public void setUid(Integer uid) {this.uid = uid;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "User{" +"uid=" + uid +", name='" + name + '\'' +", age=" + age +'}';}
}

多线程

1.多线程_线程和进程

1694511947394

进程(Processor) : 程序的一次执行。由操作系统创建并分配资源,执行一个单独的任务。 进程是系统进行资源分配和调度的独立单位,每个进程都有自己的内存空间和系统资源。进程内所有线程共享堆存储空间,保存程序中定义的对象和常量池。

线程作用 : 负责当前进程中程序的运行 , 一个进程中至少有一个线程 . 一个进程中是可以有多个线程的,这样的应用程序就称之为多线程程序 . 线程是进程内的执行单元,不分配单独的资源,执行一个单独的子任务。线程是进程内调度和分派的基本单位,共享进程资源。每个线程有自己的独立的栈存储空间,保存线程执行的方法以及基本类型的数据。 运行的 Java 程序内含至少一个主线程 main ,用户可以在 Java 程序中自定义并调用多个线程。 JVM 垃圾回收线程也是一个独立的线程。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

并发:同一个时刻多个线程同时操作了同一个数据 , 多个任务交替使用 CPU 核心工作,以提高 CPU 利用率。

并行:同一个时刻多个线程同时执行不同的程序 , 多个CPU核心同时工作,处理不同的任务。

2.CPU调度

1.分时调度:指的是让所有的线程轮流获取CPU使用权,并且平均分配每个线程占用的cpu的时间片
2.抢占式调度:多个线程轮流抢占CPU使用权,哪个线程先抢到,哪个线程先执行,一般都是优先级高的抢到CPU使用权的概率大,我们java程序都是抢占式调度

线程的运行状态 : 线程除创建状态 New 和结束状态 Terminate 外,主要有以下几种运行状态:

NEW(新建) : 线程刚被创建,但是并未启动。还没调用start方法。

运行 : (Running) CPU 正在执行线程。

就绪 : (Runnable) 线程一切就绪,等待 CPU 执行。

运行/就绪状态 统称为可运行状态 Runnable。 Java 程序中,线程在 运行/就绪状态 之间的切换由 JVM 自动调度,开发者无法获知。线程之间的调度采用分优先级多队列时间片轮转算法。进程在执行完 CPU 时间片切换到就绪状态之前会先保存自己的状态,下次进入运行状态时再重新加载。

阻塞 : (Blocked) 线程因缺少其他资源,比如请求资源被上锁而暂停执行。在获得资源后进入就绪状态。 一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。

等待 : (Waitting) 线程接受了等待指令,释放资源暂停执行。在超时/接受唤醒指令后进入就绪状态。 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、Object.wait。

Terminated(被终止) : 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。或者调用过时方法stop()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3.主线程介绍

在CPU和内存之间专门为main开辟的通道叫做主线程

主线程专门运行main方法的

1694513606433

创建线程的方式(重点)

1.第一种方式_extends Thread

步骤 :

​ ①定义类 , 继承Thread类(Thread是一个线程类)

​ ②重写Thread中的run方法 , 设置线程任务(自定义的线程需要干什么 , 将业务写进run())

​ ③创建自定义线程类对象

​ ④调用Thread中的start方法(使线程开始执行 ; Java虚拟机会调用线程中的 run 方法)

public class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 3; i++) {System.out.println("我是MyThread....");}}
}
public class Test01 {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();	//开启线程 , jvm自动调用重写的run方法for (int i = 0; i < 3; i++) {System.out.println("我是主线程...");}}
}

2.多线程在内存中的运行原理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当有多个线程开启时 , 进程会为每个线程独自开启新线程的栈空间

注意 : 同一个线程对象 , 不可以连续调用多个start方法

如果需要开启多个线程 , 需要重新new

3.Thread类中的方法

1.void start() 开启线程,jvm会自动执行run方法
2.String getName() 获取线程名字
3.static Thread currentThread()  -> 获取的是当前正在执行的线程对象,此方法在哪个线程中用,获取的就是哪个线程对象 
4.void setName(String name) -> 给线程设置名字
5.static void sleep(long time)->线程睡眠,传递毫秒值,时间超时,线程自动醒来,自动继续执行   
public class MyThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 3; i++) {Thread.sleep(1000l);System.out.println(getName()+"线程正在执行....");   //getName()  获取线程名字   因为继承了Thread,可以直接调用}}
}
public class Test01 {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();		//开启线程 , jvm自动调用重写的run方法myThread.setName("haha");	//修改线程名字for (int i = 0; i < 3; i++) {Thread.sleep(1000l);	//线程睡眠1秒System.out.println(Thread.currentThread().getName()+"线程正在执行..."); //static Thread currentThread()   获取的是当前正在执行的线程对象}}
}
//输出
main线程正在执行...
haha线程正在执行....
main线程正在执行...
haha线程正在执行....
main线程正在执行...
haha线程正在执行....

4.第二种方式_实现Runnable接口

步骤 :

​ ①定义一个类 , 实现Runnable接口

​ ②重写run方法 , 设置线程任务

​ ③创建自定义的线程类对象

​ ④利用Thread中的构造方法 : Thread(Runnable target) , 创建实现类对象 , 放到Thread中

​ ⑤调用start方法 , 启动线程

public class MyThread_implements implements Runnable{@Overridepublic void run() {try {Thread.sleep(100L);} catch (InterruptedException e) {throw new RuntimeException(e);}for (int i = 0; i < 3; i++) {System.out.println(Thread.currentThread().getName()+"线程正在执行....");}}
}
public class Test02 {public static void main(String[] args) throws InterruptedException {MyThread_implements myThread_implements = new MyThread_implements();Thread thread = new Thread(myThread_implements);thread.start();for (int i = 0; i < 3; i++) {Thread.sleep(100l);System.out.println(Thread.currentThread().getName()+"线程正在执行...");}}
}

问题 : 为什么再run方法中处理异常只能使用try_catch?

因为Thread中的run方法没有抛异常 , 子类重写父类之后也不抛 , 只能try_catch自己解决

5.两种实现多线程的方式区别

继承extends Thread : 由于继承只能单继承 , 如果某个场景它有父类也需要继承 , 就无法继承Thread了 , 所以有局限性

实现implement Runnable : 接口可以多继承多实现 , 解决了继承的局限性 , 一个类继承一个父类的同 时可以实现一个或多个接口 -----> 推荐使用

6.第三种方式_匿名内部类创建多线程

匿名内部类回顾:一种格式代表子类对象或实现类对象使用:new 接口/抽象父类(){重写方法}.重写的方法();接口/抽象类 对象名 = new 接口/抽象父类(){重写方法}对象名.重写的方法();
public class Test03Niming {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 3; i++) {System.out.println(Thread.currentThread().getName()+"匿名线程正在执行...");}}}).start();for (int i = 0; i < 3; i++) {System.out.println(Thread.currentThread().getName()+"主线程正在执行...");}}
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

线程安全

问 : 什么时候出现线程安全问题 ?

答 : 当多个线程访问同一个资源时 , 可能会出现线程安全问题

1.线程安全问题 —>线程不安全代码

public class MyTicket implements Runnable{int ticket = 100;@Overridepublic void run() {while(true){try {Thread.sleep(100L);} catch (InterruptedException e) {throw new RuntimeException(e);}if (ticket>0){System.out.println(Thread.currentThread().getName()+"买了第"+ticket+"张票");}ticket--;}}
}
public class Test01 {public static void main(String[] args) {MyTicket myTicket = new MyTicket();Thread thread1 = new Thread(myTicket,"柳岩");Thread thread2 = new Thread(myTicket,"涛哥");Thread thread3 = new Thread(myTicket,"金莲");thread1.start();thread2.start();thread3.start();}
}

原因 : CPU在多个线程中做高速切换

2.解决线程安全问题的第一种方式(使用同步代码块)

格式:synchronized(任意对象->锁对象){可能出现的线程不安全的代码}执行流程:某一个线程抢到锁,进入内部执行,其他线程就抢不到锁了,只能等待,等着执行的线程出了代码块,将锁释放,其他线程才有可能抢到锁对象,去执行
public class Ticket implements Runnable{Integer ticket = 50;@Overridepublic void run() {while (true){try {Thread.sleep(100L);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (this){if(ticket > 0){System.out.println(Thread.currentThread().getName()+"抢到了第"+ticket+"张票");ticket--;}else{return ;}}}}
}
public class Test04 {public static void main(String[] args) {Ticket ticket = new Ticket();Thread t1 = new Thread(ticket, "张三");Thread t2 = new Thread(ticket, "李四");Thread t3 = new Thread(ticket, "王五");t1.start();t2.start();t3.start();}
}

3.解决线程安全问题的第二种方式:同步方法

3.1.普通同步方法

1.格式:public synchronized 返回值类型 方法名(参数){方法体return 结果}public 返回值类型 方法名(参数){synchronized(this){方法体return 结果}}2.默认锁:this
public class Ticket1 implements Runnable{Integer ticket = 50;@Overridepublic void run() {while (true){try {Thread.sleep(100l);} catch (InterruptedException e) {throw new RuntimeException(e);}method();if(ticket == 0){return;}}}/*//采用synchronized同步方法public synchronized void method(){if(ticket > 0){System.out.println(Thread.currentThread().getName()+"抢到了第"+ticket+"张票");ticket--;}}*/public void method(){synchronized (this){if(ticket > 0){System.out.println(Thread.currentThread().getName()+"抢到了第"+ticket+"张票");ticket--;}}}
}
public class Test05 {public static void main(String[] args) {Ticket1 ticket1 = new Ticket1();Thread t1 = new Thread(ticket1, "张三");Thread t2 = new Thread(ticket1, "李四");Thread t3 = new Thread(ticket1, "王五");t1.start();t2.start();t3.start();}
}

3.2.静态同步方法

1.格式:public static synchronized 返回值类型 方法名(参数){方法体return 结果}2.默认锁:当前类.class
public class Ticket2 implements Runnable{static Integer ticket = 50;@Overridepublic void run() {while (true){try {Thread.sleep(100l);} catch (InterruptedException e) {throw new RuntimeException(e);}method();if(ticket == 0){return;}}}/*//采用synchronized同步方法public static synchronized void method(){if(ticket > 0){System.out.println(Thread.currentThread().getName()+"抢到了第"+ticket+"张票");ticket--;}}*/public static void method(){synchronized (Ticket2.class){if(ticket > 0){System.out.println(Thread.currentThread().getName()+"抢到了第"+ticket+"张票");ticket--;}}}
}
public class Test06 {public static void main(String[] args) {Ticket2 ticket2 = new Ticket2();Thread t1 = new Thread(ticket2, "张三");Thread t2 = new Thread(ticket2, "李四");Thread t3 = new Thread(ticket2, "王五");t1.start();t2.start();t3.start();}
}

死锁

1.死锁介绍(锁嵌套就有可能产生死锁)

​ 指的是两个或者两个以上的线程在执行的过程中,由于竞争同步锁而产生的一种阻塞现象;如果没有外力的作用,他们将无法继续执行下去,这种情况就称之为死锁.

1694519025452
根据上图所示:线程T1正在持有R1,但是T1线程必须再拿到R2,才能继续执行
而线程T2正在持有R2,但是T2线程需要再拿到R1,才能继续执行
此时两个线程处于互相等待的状态,就是死锁,在程序中的死锁将出现在同步代码块的嵌套中

2.死锁的分析

1694519069437

3.代码实现

public class LockA {public static LockA lockA = new LockA();
}
public class LockB {public static LockB lockB = new LockB();
}
public class DieLock implements Runnable {private boolean flag;public DieLock(boolean flag) {this.flag = flag;}@Overridepublic void run() {if (flag) {synchronized (LockA.lockA) {System.out.println("if...lockA");synchronized (LockB.lockB) {System.out.println("if...lockB");}}} else {synchronized (LockB.lockB) {System.out.println("else...lockB");synchronized (LockA.lockA) {System.out.println("else...lockA");}}}}
}
public class Test01 {public static void main(String[] args) {DieLock dieLock1 = new DieLock(true);DieLock dieLock2 = new DieLock(false);new Thread(dieLock1).start();new Thread(dieLock2).start();}
}

lag = flag;
}

@Override
public void run() {if (flag) {synchronized (LockA.lockA) {System.out.println("if...lockA");synchronized (LockB.lockB) {System.out.println("if...lockB");}}} else {synchronized (LockB.lockB) {System.out.println("else...lockB");synchronized (LockA.lockA) {System.out.println("else...lockA");}}}}

}


~~~java
public class Test01 {public static void main(String[] args) {DieLock dieLock1 = new DieLock(true);DieLock dieLock2 = new DieLock(false);new Thread(dieLock1).start();new Thread(dieLock2).start();}
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pyechart练习(一):画图小练习

1、使用Map制作全球人口分布图 import math import osimport matplotlib.pyplot as plt from pyecharts.charts import Map from pyecharts import options as opts# 只有部分国家的人口数据 POPULATION [["China", 1420062022], ["India", 1368737513],…

AI文本创作在百度App发文的实践

作者 | 内容生态端团队 导读 大语言模型&#xff08;LLM&#xff09;指包含数百亿&#xff08;或更多&#xff09;参数的语言模型&#xff0c;这些模型通常在大规模数据集上进行训练&#xff0c;以提高其性能和泛化能力。在内容创作工具接入文心一言AI能力后&#xff0c;可以为…

大数据课程L2——网站流量项目的算法分析数据处理

文章作者邮箱:yugongshiye@sina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 了解网站流量项目的算法分析; ⚪ 了解网站流量项目的数据处理; 一、项目的算法分析 1. 概述 网站流量统计是改进网站服务的重要手段之一,通过获取用户在网站的行为,可以分析出哪些内…

学习Bootstrap 5的第八天

目录 加载器 彩色加载器 实例 闪烁加载器 实例 加载器大小 实例 加载器按钮 实例 分页 分页的基本结构 实例 活动状态 实例 禁用状态 实例 分页大小 实例 分页对齐 实例 面包屑&#xff08;Breadcrumbs&#xff09; 实例 加载器 彩色加载器 在 Bootstr…

【css | loading】好看的loading特效

示例&#xff1a; https://code.juejin.cn/pen/7277764394618978365 html <div class"pl"><div class"pl__dot"></div><div class"pl__dot"></div><div class"pl__dot"></div><div c…

科技云报道:青云科技为何成为IDC云转型的“神队友”?

科技云报道原创。 如今随着出海企业数量的不断增长&#xff0c;跨境业务也逐渐从蓝海变红海&#xff0c;从“价格战”到“智能战”。 一个明显的变化&#xff0c;来自企业对于出海效率的提升。《埃森哲2022中国企业国际化研究》指出&#xff0c;企业想要在出海浪潮中取胜&…

顺序表详解(接口详解)

顺序表&#xff08;接口详解&#xff09;&#x1f996; 1.线性表2.顺序表2.1 概念及结构 3.接口的实现3.1 定义SeqList3.2 初始化3.3 销毁3.4 打印3.5 扩容3.6 数据插入1.头插2.尾插3.下标插入 3.7 数据删除1.头删2.尾删3.下表删除 3.8 查询数据3.9 数据修改 4.顺序表存在的部分…

工厂设计模式

github&#xff1a;GitHub - QiuliangLee/pattern: 设计模式 概念 根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式&#xff0c;根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。 简单工厂模式、工厂方法模式和抽象工厂模式有何区别&#xff1f; - 知…

【SpringCloudAlibaba】Seata分布式事务使用

文章目录 分布式事务问题示例Seata概述、官网一个典型的分布式事务过程处理过程全局GlobalTransactional分布式交易解决方案流程图 Seata安装下载修改conf目录下的application.yml配置文件dashboard demo 分布式事务问题示例 单体应用被拆分成微服务应用&#xff0c;原来的三个…

【微信小程序开发】一文学会使用视图组件进行界面设计

引言 在小程序开发中&#xff0c;界面设计是非常重要的一环。本文将介绍如何学习使用小程序的视图组件进行界面设计&#xff0c;并提供代码示例。 文章目录 引言1. 小程序视图组件简介2. 视图组件的使用方法2.1. 组件的引入2.2. 组件的使用2.3. 组件的事件绑定2.4. 组件的样式设…

微火资讯快报:共享wifi项目怎么样?

共享WiFi项目一直以来都是一个热门的创业方向&#xff0c;它通过将公共场所的WiFi热点转换成二维码&#xff0c;使用户扫码就可轻松地连接并使用网络&#xff0c;而商家也可以通过该平台实现广告宣传、营销推广等功能。下面就让我们来详细了解一下共享WiFi项目的各个方面。 市场…

推荐10个AI人工智能技术网站(一键收藏,应有尽有)

1、Mental AI MentalAI&#xff08;https://ai.ciyundata.com/&#xff09;是一种基于文心大模型的知识增强大语言模型&#xff0c;专注于自然语言处理&#xff08;NLP&#xff09;领域的技术研发。它具备强大的语义理解和生成能力&#xff0c;能够处理各种复杂的自然语言任务。…