当前位置: 首页 > news >正文

ThreadLoca基本使用以及与synchronized的区别

文章目录

    • 1. ThreadLocal介绍
      • 1.1 官方介绍
      • 1.2 基本使用
        • 1.2.1 常用方法
        • 1.2.2 使用案例
      • 1.3 ThreadLocal类与synchronized关键字
        • 1.3.1 synchronized同步方式
        • 1.3.2 ThreadLocal与synchronized的区别
    • 2. 运用场景_事务案例
      • 2.1 转账案例
        • 2.1.1 场景构建
        • 2.1.2 引入事务
      • 2.2 常规解决方案
        • 2.2.1 常规方案的实现
        • 2.2.2 常规方案的弊端
      • 2.3 ThreadLocal解决方案
        • 2.3.1 ThreadLocal方案的实现
        • 2.3.2 ThreadLocal方案的好处

1. ThreadLocal介绍

1.1 官方介绍

/*** This class provides thread-local variables.  These variables differ from* their normal counterparts in that each thread that accesses one (via its* {@code get} or {@code set} method) has its own, independently initialized* copy of the variable.  {@code ThreadLocal} instances are typically private* static fields in classes that wish to associate state with a thread (e.g.,* a user ID or Transaction ID).** <p>For example, the class below generates unique identifiers local to each* thread.* A thread's id is assigned the first time it invokes {@code ThreadId.get()}* and remains unchanged on subsequent calls.* <pre>* import java.util.concurrent.atomic.AtomicInteger;** public class ThreadId {*     // Atomic integer containing the next thread ID to be assigned*     private static final AtomicInteger nextId = new AtomicInteger(0);**     // Thread local variable containing each thread's ID*     private static final ThreadLocal&lt;Integer&gt; threadId =*         new ThreadLocal&lt;Integer&gt;() {*             &#64;Override protected Integer initialValue() {*                 return nextId.getAndIncrement();*         }*     };**     // Returns the current thread's unique ID, assigning it if necessary*     public static int get() {*         return threadId.get();*     }* }* </pre>* <p>Each thread holds an implicit reference to its copy of a thread-local* variable as long as the thread is alive and the {@code ThreadLocal}* instance is accessible; after a thread goes away, all of its copies of* thread-local instances are subject to garbage collection (unless other* references to these copies exist).** @author  Josh Bloch and Doug Lea* @since   1.2*/
public class ThreadLocal<T> {...

​ 从Java官方文档中的描述:ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程上下文。

我们可以得知 ThreadLocal 的作用是:提供线程内的局部变量,不同的线程之间
不会相互干扰,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数
或组件之间一些公共变量传递的复杂度。
总结:
1. 线程并发: 在多线程并发的场景下
2. 传递数据: 我们可以通过ThreadLocal在同一线程,不同组件中传递公共变量
3. 线程隔离: 每个线程的变量都是独立的,不会互相影响

1.2 基本使用

1.2.1 常用方法

​ 在使用之前,我们先来认识几个ThreadLocal的常用方法

方法声明描述
ThreadLocal()创建ThreadLocal对象
public void set( T value)设置当前线程绑定的局部变量
public T get()获取当前线程绑定的局部变量
public void remove()移除当前线程绑定的局部变量

1.2.2 使用案例

我们来看下面这个案例, 感受一下ThreadLocal 线程隔离的特点: 
public class MyDemo {private String content;private String getContent() {return content;}private void setContent(String content) {this.content = content;}public static void main(String[] args) {MyDemo demo = new MyDemo();for (int i = 0; i < 5; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {demo.setContent(Thread.currentThread().getName() + "的数据");System.out.println("-----------------------");System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());}});thread.setName("线程" + i);thread.start();}}
}

打印结果:
在这里插入图片描述

​ 从结果可以看出多个线程在访问同一个变量的时候出现的异常,线程间的数据没有隔离。下面我们来看下采用 ThreadLocal 的方式来解决这个问题的例子。

public class MyDemo {private static ThreadLocal<String> tl = new ThreadLocal<>();private String content;private String getContent() {return tl.get();}private void setContent(String content) {tl.set(content);}public static void main(String[] args) {MyDemo demo = new MyDemo();for (int i = 0; i < 5; i++) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {demo.setContent(Thread.currentThread().getName() + "的数据");System.out.println("-----------------------");System.out.println(Thread.currentThread().getName() + "--->" + demo.getContent());}});thread.setName("线程" + i);thread.start();}}
}

打印结果:
在这里插入图片描述

从结果来看,这样很好的解决了多线程之间数据隔离的问题,十分方便。

1.3 ThreadLocal类与synchronized关键字

1.3.1 synchronized同步方式

​ 这里可能有的朋友会觉得在上述例子中我们完全可以通过加锁来实现这个功能。我们首先来看一下用synchronized代码块实现的效果:

public class Demo02 {private String content;public String getContent() {return content;}public void setContent(String content) {this.content = content;}public static void main(String[] args) {Demo02 demo02 = new Demo02();for (int i = 0; i < 5; i++) {Thread t = new Thread(){@Overridepublic void run() {synchronized (Demo02.class){demo02.setContent(Thread.currentThread().getName() + "的数据");System.out.println("-------------------------------------");String content = demo02.getContent();System.out.println(Thread.currentThread().getName() + "--->" + content);}}};t.setName("线程" + i);t.start();}}
}

打印结果:

​			[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eiSxFVJd-1677730042406)(img\007.png)]

​ 从结果可以发现, 加锁确实可以解决这个问题,但是在这里我们强调的是线程数据隔离的问题,并不是多线程共享数据的问题, 在这个案例中使用synchronized关键字是不合适的。

1.3.2 ThreadLocal与synchronized的区别

​ 虽然ThreadLocal模式与synchronized关键字都用于处理多线程并发访问变量的问题, 不过两者处理问题的角度和思路不同。

synchronizedThreadLocal
原理同步机制采用’以时间换空间’的方式, 只提供了一份变量,让不同的线程排队访问ThreadLocal采用’以空间换时间’的方式, 为每一个线程都提供了一份变量的副本,从而实现同时访问而相不干扰
侧重点多个线程之间访问资源的同步多线程中让每个线程之间的数据相互隔离
总结: 在刚刚的案例中,虽然使用ThreadLocal和synchronized都能解决问题,
但是使用ThreadLocal更为合适,因为这样可以使程序拥有更高的并发性。

2. 运用场景_事务案例

​ 通过以上的介绍,我们已经基本了解ThreadLocal的特点。但是它具体是运用在什么场景中呢? 接下来让我们看一个案例: 事务操作。

2.1 转账案例

2.1.1 场景构建

​ 这里我们先构建一个简单的转账场景: 有一个数据表account,里面有两个用户Jack和Rose,用户Jack 给用户Rose 转账。

​ 案例的实现主要用mysql数据库,JDBC 和 C3P0 框架。以下是详细代码 :

​ (1) 项目结构

在这里插入图片描述

​ (2) 数据准备

-- 使用数据库
use test;
-- 创建一张账户表
create table account(id int primary key auto_increment,name varchar(20),money double
);
-- 初始化数据
insert into account values(null, 'Jack', 1000);
insert into account values(null, 'Rose', 0);

​ (3) C3P0配置文件和工具类

<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config><!--  连接参数 --><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property><property name="user">root</property><property name="password">1234</property><!-- 连接池参数 --><property name="initialPoolSize">5</property><property name="maxPoolSize">10</property><property name="checkoutTimeout">3000</property>
</default-config></c3p0-config>

​ (4) 工具类 : JdbcUtils

package com.itheima.transfer.utils;import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.SQLException;public class JdbcUtils {// c3p0 数据库连接池对象属性private static final ComboPooledDataSource ds = new ComboPooledDataSource();// 获取连接public static Connection getConnection() throws SQLException {return ds.getConnection();}//释放资源public static void release(AutoCloseable... ios){for (AutoCloseable io : ios) {if(io != null){try {io.close();} catch (Exception e) {e.printStackTrace();}}}}public static void commitAndClose(Connection conn) {try {if(conn != null){//提交事务conn.commit();//释放连接conn.close();}} catch (SQLException e) {e.printStackTrace();}}public static void rollbackAndClose(Connection conn) {try {if(conn != null){//回滚事务conn.rollback();//释放连接conn.close();}} catch (SQLException e) {e.printStackTrace();}}
}

​ (5) dao层代码 : AccountDao

package com.itheima.transfer.dao;import com.itheima.transfer.utils.JdbcUtils;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;public class AccountDao {public void out(String outUser, int money) throws SQLException {String sql = "update account set money = money - ? where name = ?";Connection conn = JdbcUtils.getConnection();PreparedStatement pstm = conn.prepareStatement(sql);pstm.setInt(1,money);pstm.setString(2,outUser);pstm.executeUpdate();JdbcUtils.release(pstm,conn);}public void in(String inUser, int money) throws SQLException {String sql = "update account set money = money + ? where name = ?";Connection conn = JdbcUtils.getConnection();PreparedStatement pstm = conn.prepareStatement(sql);pstm.setInt(1,money);pstm.setString(2,inUser);pstm.executeUpdate();JdbcUtils.release(pstm,conn);}
}

​ (6) service层代码 : AccountService

package com.itheima.transfer.service;import com.itheima.transfer.dao.AccountDao;
import java.sql.SQLException;public class AccountService {public boolean transfer(String outUser, String inUser, int money) {AccountDao ad = new AccountDao();try {// 转出ad.out(outUser, money);// 转入ad.in(inUser, money);} catch (Exception e) {e.printStackTrace();return false;}return true;}
}

​ (7) web层代码 : AccountWeb

package com.itheima.transfer.web;import com.itheima.transfer.service.AccountService;public class AccountWeb {public static void main(String[] args) {// 模拟数据 : Jack 给 Rose 转账 100String outUser = "Jack";String inUser = "Rose";int money = 100;AccountService as = new AccountService();boolean result = as.transfer(outUser, inUser, money);if (result == false) {System.out.println("转账失败!");} else {System.out.println("转账成功!");}}
}

2.1.2 引入事务

​ 案例中的转账涉及两个DML操作: 一个转出,一个转入。这些操作是需要具备原子性的,不可分割。不然就有可能出现数据修改异常情况。

public class AccountService {public boolean transfer(String outUser, String inUser, int money) {AccountDao ad = new AccountDao();try {// 转出ad.out(outUser, money);// 模拟转账过程中的异常int i = 1/0;// 转入ad.in(inUser, money);} catch (Exception e) {e.printStackTrace();return false;}return true;}
}

​ 所以这里就需要操作事务,来保证转出和转入操作具备原子性,要么同时成功,要么同时失败。

(1) JDBC中关于事务的操作的api

Connection接口的方法作用
void setAutoCommit(false)禁用事务自动提交(改为手动)
void commit();提交事务
void rollback();回滚事务

(2) 开启事务的注意点:

  • 为了保证所有的操作在一个事务中,案例中使用的连接必须是同一个: service层开启事务的connection需要跟dao层访问数据库的connection保持一致

  • 线程并发情况下, 每个线程只能操作各自的 connection

2.2 常规解决方案

2.2.1 常规方案的实现

基于上面给出的前提, 大家通常想到的解决方案是 :

  • 传参: 从service层将connection对象向dao层传递
  • 加锁

以下是代码实现修改的部分:

​ (1 ) AccountService 类

package com.itheima.transfer.service;import com.itheima.transfer.dao.AccountDao;
import com.itheima.transfer.utils.JdbcUtils;
import java.sql.Connection;public class AccountService {public boolean transfer(String outUser, String inUser, int money) {AccountDao ad = new AccountDao();//线程并发情况下,为了保证每个线程使用各自的connection,故加锁synchronized (AccountService.class) {Connection conn = null;try {conn = JdbcUtils.getConnection();//开启事务conn.setAutoCommit(false);// 转出ad.out(conn, outUser, money);// 模拟转账过程中的异常
//            int i = 1/0;// 转入ad.in(conn, inUser, money);//事务提交JdbcUtils.commitAndClose(conn);} catch (Exception e) {e.printStackTrace();//事务回滚JdbcUtils.rollbackAndClose(conn);return false;}return true;}}
}

​ (2) AccountDao 类 (这里需要注意的是: connection不能在dao层释放,要在service层,不然在dao层释放,service层就无法使用了)

package com.itheima.transfer.dao;import com.itheima.transfer.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;public class AccountDao {public void out(Connection conn, String outUser, int money) throws SQLException{String sql = "update account set money = money - ? where name = ?";//注释从连接池获取连接的代码,使用从service中传递过来的connection
//        Connection conn = JdbcUtils.getConnection();PreparedStatement pstm = conn.prepareStatement(sql);pstm.setInt(1,money);pstm.setString(2,outUser);pstm.executeUpdate();//连接不能在这里释放,service层中还需要使用
//        JdbcUtils.release(pstm,conn);JdbcUtils.release(pstm);}public void in(Connection conn, String inUser, int money) throws SQLException {String sql = "update account set money = money + ? where name = ?";
//        Connection conn = JdbcUtils.getConnection();PreparedStatement pstm = conn.prepareStatement(sql);pstm.setInt(1,money);pstm.setString(2,inUser);pstm.executeUpdate();
//        JdbcUtils.release(pstm,conn);JdbcUtils.release(pstm);}
}

2.2.2 常规方案的弊端

上述方式我们看到的确按要求解决了问题,但是仔细观察,会发现这样实现的弊端:

  1. 直接从service层传递connection到dao层, 造成代码耦合度提高

  2. 加锁会造成线程失去并发性,程序性能降低

2.3 ThreadLocal解决方案

2.3.1 ThreadLocal方案的实现

像这种需要在项目中进行数据传递线程隔离的场景,我们不妨用ThreadLocal来解决:

​ (1) 工具类的修改: 加入ThreadLocal

package com.itheima.transfer.utils;import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.SQLException;public class JdbcUtils {//ThreadLocal对象 : 将connection绑定在当前线程中private static final ThreadLocal<Connection> tl = new ThreadLocal();// c3p0 数据库连接池对象属性private static final ComboPooledDataSource ds = new ComboPooledDataSource();// 获取连接public static Connection getConnection() throws SQLException {//取出当前线程绑定的connection对象Connection conn = tl.get();if (conn == null) {//如果没有,则从连接池中取出conn = ds.getConnection();//再将connection对象绑定到当前线程中tl.set(conn);}return conn;}//释放资源public static void release(AutoCloseable... ios) {for (AutoCloseable io : ios) {if (io != null) {try {io.close();} catch (Exception e) {e.printStackTrace();}}}}public static void commitAndClose() {try {Connection conn = getConnection();//提交事务conn.commit();//解除绑定tl.remove();//释放连接conn.close();} catch (SQLException e) {e.printStackTrace();}}public static void rollbackAndClose() {try {Connection conn = getConnection();//回滚事务conn.rollback();//解除绑定tl.remove();//释放连接conn.close();} catch (SQLException e) {e.printStackTrace();}}
}

​ (2) AccountService类的修改:不需要传递connection对象

package com.itheima.transfer.service;import com.itheima.transfer.dao.AccountDao;
import com.itheima.transfer.utils.JdbcUtils;
import java.sql.Connection;public class AccountService {public boolean transfer(String outUser, String inUser, int money) {AccountDao ad = new AccountDao();try {Connection conn = JdbcUtils.getConnection();//开启事务conn.setAutoCommit(false);// 转出 : 这里不需要传参了 !ad.out(outUser, money);// 模拟转账过程中的异常
//            int i = 1 / 0;// 转入ad.in(inUser, money);//事务提交JdbcUtils.commitAndClose();} catch (Exception e) {e.printStackTrace();//事务回滚JdbcUtils.rollbackAndClose();return false;}return true;}
}

​ (3) AccountDao类的修改:照常使用

package com.itheima.transfer.dao;import com.itheima.transfer.utils.JdbcUtils;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;public class AccountDao {public void out(String outUser, int money) throws SQLException {String sql = "update account set money = money - ? where name = ?";Connection conn = JdbcUtils.getConnection();PreparedStatement pstm = conn.prepareStatement(sql);pstm.setInt(1,money);pstm.setString(2,outUser);pstm.executeUpdate();//照常使用
//        JdbcUtils.release(pstm,conn);JdbcUtils.release(pstm);}public void in(String inUser, int money) throws SQLException {String sql = "update account set money = money + ? where name = ?";Connection conn = JdbcUtils.getConnection();PreparedStatement pstm = conn.prepareStatement(sql);pstm.setInt(1,money);pstm.setString(2,inUser);pstm.executeUpdate();
//        JdbcUtils.release(pstm,conn);JdbcUtils.release(pstm);}
}

2.3.2 ThreadLocal方案的好处

从上述的案例中我们可以看到, 在一些特定场景下,ThreadLocal方案有两个突出的优势:

  1. 传递数据 : 保存每个线程绑定的数据,在需要的地方可以直接获取, 避免参数直接传递带来的代码耦合问题

  2. 线程隔离 : 各线程之间的数据相互隔离却又具备并发性,避免同步方式带来的性能损失

相关文章:

ThreadLoca基本使用以及与synchronized的区别

文章目录1. ThreadLocal介绍1.1 官方介绍1.2 基本使用1.2.1 常用方法1.2.2 使用案例1.3 ThreadLocal类与synchronized关键字1.3.1 synchronized同步方式1.3.2 ThreadLocal与synchronized的区别2. 运用场景_事务案例2.1 转账案例2.1.1 场景构建2.1.2 引入事务2.2 常规解决方案2.…...

【C++】纯虚函数、纯虚析构

纯虚函数语法&#xff1a;virtual 返回值类型 函数名(参数列表) 0纯虚函数的作用&#xff1a;不用定义&#xff01;在多态中&#xff0c;通常父类中虚函数的实现是无意义的&#xff08;因为主要用子类重写的&#xff0c;父类只是为了派生子类当做一个类族的顶层出现&#xff0…...

Python 进阶小技巧:7招展开嵌套列表

大家好&#xff0c;今天给大家讲解一个Python的进阶知识点&#xff1a;如何将一个嵌套的大列表展开形成一个列表。 小编提供了7种方法供大家学习参考&#xff1a; for循环 列表推导式 使用第三方库itertools 使用sum函数 python自加&#xff08;&#xff09; 使用extend函…...

【Spring6】| Bean的作用域

目录 一&#xff1a;Bean的作用域 1. singleton&#xff08;单例&#xff09; 2. prototype&#xff08;多例&#xff09; 3. 其它scope 4. 自定义scop&#xff08;了解&#xff09; 一&#xff1a;Bean的作用域 1. singleton&#xff08;单例&#xff09; &#xff08;1…...

Qt界面美化之自定义qss样式表

原生的QT界面不好看&#xff0c;有时候需要根据美工的设计图修改样式。如果使用QML的话搞界面是快&#xff0c;但是QML有点儿吃内存&#xff0c;有时简单的功能还是用传统c的widget方便些。好在有qss&#xff0c;传统界面也可以美化的。QSS称为Qt Style Sheets也就是Qt样式表&a…...

春招进行时:“211文科硕士吐槽工资5500” HR:行情和能力决定价值

学历重要&#xff0c;还是能力重要&#xff1f; 春招进行时&#xff0c;不少学生求职遇冷&#xff0c;会把原因归结为学历水平不够高、毕业院校不够档次、专业不够热门、非一线城市就业机会少等等。 直到上海一位211大学的文科男硕士&#xff0c;吐槽招聘会提供的岗位薪资待遇…...

【DaVinci Developer专题】-45-自动生成SWC中所有Runnable对应的C文件

点击返回「Autosar从入门到精通-实战篇」总目录 案例背景(共5页精讲): 在DaVinci Developer中,以Test_A_SWC的Runnable为例,见图0-1。我们现在尝试自动生成一个包含Test_A_SWC_Init和Test_A_SWC_Main函数原型(也是适用于 C/S Port Serve Runnable)的C文件。 图0-1 目…...

redis启动和关闭服务脚本

编译安装redis&#xff0c;自己写了个脚本。 简单实现启动、关闭和 查看redis服务。 基本流程如下&#xff1a; 脚本执行&#xff0c;必须附带1个参数&#xff0c;没有参数会提示附带参数。 脚本会获取redis-server进程数量。作为开启、关闭以及查看redis服务的数据依据。 …...

windows CMD快捷键:

&#x1f431;个人主页&#xff1a;莎萌玩家&#x1f64b;‍♂️作者简介&#xff1a;全栈领域新星创作者、专注于全栈各领域技术&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01;&#x1f4ab;系列专栏&#xff1a;网络爬虫、WEB全栈开发&#x1f4e2;资料领取…...

【C/C++语言】刷题|双指针|数组|单链表

主页&#xff1a;114514的代码大冒 qq:2188956112&#xff08;欢迎小伙伴呀hi✿(。◕ᴗ◕。)✿ &#xff09; Gitee&#xff1a;庄嘉豪 (zhuang-jiahaoxxx) - Gitee.com 文章目录 目录 文章目录 前言 一、删除有序数组中的重复项 二、合并两个有序数组 三&#xff0c;移除…...

Leetcode.1487 保证文件名唯一

题目链接 Leetcode.1487 保证文件名唯一 Rating &#xff1a; 1697 题目描述 给你一个长度为 n的字符串数组 names。你将会在文件系统中创建 n个文件夹&#xff1a;在第 i 分钟&#xff0c;新建名为 names[i]的文件夹。 由于两个文件 不能 共享相同的文件名&#xff0c;因此如…...

python-星号(*)-双星号(**)-函数动态参数匹配-解包操作

文章目录1.乘法和幂运算符2.函数接收数量不固定的入参3.限制函数入参仅以关键字形式输入4. 可迭代对象解包操作5.扩展可迭代对象解包1.乘法和幂运算符 ● 单个 * 用于乘法运算 ● 两个 ** 表示幂运算 >>> 2*3 >>> 6 >>> 2**3 >>> 82.函数…...

面试官:为什么说ArrayList线程不安全?

本博客知识点收录于&#xff1a;⭐️《JavaSE系列教程》⭐️ 1&#xff09;线程安全与不安全集合 我们学习集合的时候发现集合存在由线程安全集合和线程不安全集合&#xff1b;线程安全效率低&#xff0c;安全性高&#xff1b;反之&#xff0c;线程不安全效率高&#xff0c;安…...

STP详解

STP STP全称为“生成树协议”&#xff08;Spanning Tree Protocol&#xff09;&#xff0c;是一种网络协议&#xff0c;用于在交换机网络中防止网络回路产生&#xff0c;保证网络的稳定和可靠性。它通过在网络中选择一条主路径&#xff08;树形结构&#xff09;&#xff0c;并…...

linux AWK常用命令 —— 筑梦之路

搜集整理awk常用命令&#xff0c;以便使用查询 # 打印文件第一列awk {print $1} rumenz.txt# 打印文件前两列awk {print $1,$2} rumenz.txt# 打印文件最后一列awk {print $NF} rumenz.txt# 打印文件总行数awk END{print NR} rumenz.txt# 打印文件第一行awk NR1{print} rumenz.…...

SpringCloud:服务拆分及远程调用

目录 SpringCloud&#xff1a;服务拆分及远程调用 1、服务拆分 2、远程调用 SpringCloud&#xff1a;服务拆分及远程调用 SpringCloud是目前国内使用最广泛的微服务框架。 官网地址: Spring Cloud SpringCloud集成了各种微服务功能组件&#xff0c;并基于SpringBoot实现了…...

网络应用之javascript函数定义和调用

函数定义和调用学习目标能够写出函数的定义和调用方式1. 函数定义函数就是可以重复使用的代码块, 使用关键字 function 定义函数。<script type"text/javascript">// 函数定义function fnAlert(){alert(hello!);} </script>2. 函数调用函数调用就是函数名…...

使用VNC远程连接Ubuntu - 内网穿透实现公网远程办公

写在前面&#xff1a;博主是一只经过实战开发历练后投身培训事业的“小山猪”&#xff0c;昵称取自动画片《狮子王》中的“彭彭”&#xff0c;总是以乐观、积极的心态对待周边的事物。本人的技术路线从Java全栈工程师一路奔向大数据开发、数据挖掘领域&#xff0c;如今终有小成…...

JavaScript Date 日期对象

文章目录JavaScript Date 日期对象Date 对象Date 对象属性Date 对象方法创建日期设置日期两个日期比较JavaScript Date 日期对象 日期对象用于处理日期和时间。 Date 对象 Date 对象用于处理日期与实际。 创建 Date 对象&#xff1a; new Date(). 以上四种方法同样可以创建…...

婴幼儿常见八大疾病及护理方法

在1岁之前&#xff0c;婴儿的体质还没有完全发育&#xff0c;很容易生病&#xff0c;大多数婴儿在1岁之后都会更好。今天&#xff0c;新的稀有婴儿育儿专家组织了一些婴儿最容易患的疾病和护理方法。1、新生儿黄疸宝宝出生后&#xff0c;你可能会注意到他的皮肤发黄。别担心&am…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案

这个问题我看其他博主也写了&#xff0c;要么要会员、要么写的乱七八糟。这里我整理一下&#xff0c;把问题说清楚并且给出代码&#xff0c;拿去用就行&#xff0c;照着葫芦画瓢。 问题 在继承QWebEngineView后&#xff0c;重写mousePressEvent或event函数无法捕获鼠标按下事…...

​​企业大模型服务合规指南:深度解析备案与登记制度​​

伴随AI技术的爆炸式发展&#xff0c;尤其是大模型&#xff08;LLM&#xff09;在各行各业的深度应用和整合&#xff0c;企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者&#xff0c;还是积极拥抱AI转型的传统企业&#xff0c;在面向公众…...

篇章二 论坛系统——系统设计

目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...