Java之JDBC数据库编程

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: Java之JDBC数据库编程


什么是数据库API:

先来看看百度是怎么说的:

API(Application Programming Interface, 应用程序 编程接口)是一些预先定义的 函数 ,目的是提供 应用程序 与开发人员基于某 软件 或硬件得以访问一组 例程 的能力,而又无需访问源码,或理解内部工作 机制 的细节。

就好比, 你家门口有一个饭店, 这个饭店为你提供了以下服务:

  1. 预定座位
  2. 提前点餐
  3. 在线支付
  4. 外卖送餐

.......

API就相当于这个饭店的门面,只有你知道这个门面,你才能享受他的服务.这个饭店就相当于一个数据库, 而这些服务就是API接口提供的操作方法, 或者称为函数. 只不过这些服务都是在代码层次的, 不同数据库都提供了不同的API接口. 程序员就可以通过这些接口来调用里面的方法,以便更快速地操作数据.

什么是java-JDBC编程

在处理一些复杂的SQL语句, 或者是有一个数据量非常大的数据集等着被写入数据库, 那么这种一个一个使用SQL语句插入的效率是非常低效和麻烦的. 于是就有了用java语句来操作数据库的这种方法, 但是众所周知, 数据库不只有MySQL一个, 还有oracle和SQL server等, 他们都提供了不同的API接口, 如果一个java程序员要操作MySQL数据库, 那么他就要去书序MySQL的API接口, 如果是oracle,那么就要去学习oracle的API接口, 因此程序员的学习成本将会变得很高.

然后sun公司就为这些数据库规范了一套API接口, 各个数据库厂商就按这个规范提供这套API接口的实现. 这套规范并不是说直接把这些数据库原来的API接口直接覆盖了, 而是把在原来的基础上把这些接口封装一下, 然后供JDBC使用. 于是这些厂商就提供了封装自身API的程序.

这个程序用来完成对API的转换, 将其转换为JDBC可以使用的API, 这些程序就被称为数据库驱动包.如果java程序员要想进行数据库开发, 就需要在其项目中导入 对应数据库的驱动包, 才能编写代码. 平时我们也可能看到常用的硬件驱动设备. 硬件驱动是让操作系统认识新的硬件设备, 数据库的驱动是让JDBC认识数据库的API接口.

如何导入数据库?

1.创建一个java项目

创建一个java项目

这个就不多讲~~

2.驱动包下载

驱动包是数据库厂商提供的, 对于MySQL这种开源数据库, 我们可以怎么获取他的驱动包?

  1. MySQL官方网站获取(但是MySQL被oracle合并之后, 官网也合并了)
  2. GitHub
  3. maven中央仓储

这里主要讲解maven下载的方式

什么是中央仓储? 比如你要下载一个软件, 你可以去手机app商店下载, 也可以去这个软件的官网下载. 这个maven就像一个app商店, 里面集合了很多常用的软件. maven是一个软件, 这个中央仓储是一个服务器, 这个服务器托管了各种软件程序包, 所以就可以通过maven这个软件访问仓储服务器, 来下载程序包.

maven仓库 <-- maven网址

在其中搜索mysql即可, 然后选择MySQL Connector Java :

如何检索出MySQL的API程序包

点进去之后可以看到里面有很多版本, 这些版本大致分为:

2.0 3.0 3.1 5.0 5.1 6.0 8.0 这几个版本,

但是这些版本需要和我们的数据库服务器相匹配

这个 ? vulnerabilities 也就是漏洞的意思, 是一些bug, 可能会带来一些风险, 黑客可能利用这个漏洞来攻击你的电脑.

数据库版本相关

注意: 数据库服务器的版本要和驱动包的大版本一致. 例如 数据库服务器的是5.0系列, 驱动包也需要

使用5.0版本.

我们选择5.1.49版本的驱动包 进入5.1.49的详细页面, 然后点击jar开始下载:

这种 .jar 是java发布程序的典型方式, java通过.java源文件编译成.class文件, 然后jvm来解释执行.class文件. 每一个.Java文件对应一个.class文件, 但是如果一个项目里面.java文件很多呢? 那么就会将一大堆的.class文件, 给压缩成类似.rar / .zip的.jar压缩包文件, 将jar包打包给别人,别人就可以直接使用jvm来使用.

3.驱动包导入(IDEA)

这个jar包并不是单独地去运行, 而是将其导入创建的Java项目当中, 然后可以调用其中的方法和类来进行编程!!!

这里的导入不用解压, jvm会自动识别.

导入完之后还需要将这个目录标记为 项目的库:

将你创建的包含了驱动包的文件夹设置为项目库, 点击Add as Library

设置完之后, idea 就能识别这个目录里面的jar包, 从而调用里面的类和方法.

这样就可以看到里面的一些类和文件

编写JDBC代码

JDBC需要通过以下步骤来完成开发

  1. 创建并初始化一个数据源
  2. 和数据库服务器建立连接
  3. 构造一个SQL语句
  4. 执行SQL语句
  5. 释放必要的资源

1.创建数据源

数据源:描述数据从哪来, 也就是描述数据库服务器在哪, 也就是DataSource:

public class JDBC {
    public static void main(String[] args){
        DataSource dataSource = new MysqlDataSource(); // 使用驱动包中的类
    }
}

此处的DataSource是一个接口, 这里使用MysqlDataSource的向上转型, 然而MysqlDataSource里面的一些方法是父类DataSource里面没有的, 因此要使用这些子类中有的而父类中没有的方法就需要进行向下转型, 例如((MySQLDataSource)DataSource).strUtr();

当然你也可以不使用向上转型:

public class JDBC {
    public static void main(String[] args){
        MysqlDataSource dataSource = new MysqlDataSource(); // 使用驱动包中的类
    }
}

其中URL是一个网络常用术语, 描述网络资源的所在位置, 例如:

url:"jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&useSSL=false"

public class JDBC {
    public static void main(String[] args){
        DataSource dataSource = new MysqlDataSource(); // 使用驱动包中的类
       // 创建数据源
         ((MysqlDataSource)dataSource).setUrl(
        "jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&useSSL=false"
        );
    }
}

其中jdbc是固定的格式, 第一个冒号' : '后面的主要是看是啥数据库, 如果你是MySQL, 那么就写mysql.

我们前面提过, mysql是一个客户端服务器式的结构, 客户端和服务器之间通过网络来通信, 网络上确定主机的位置就是通过ip地址来确定的, 于是在数据库后面的' :// '后面写入ip地址:127.0.0.1, 这叫做环回ip. 表示你自己的当前的主机, 因为当前数据库客户端(也就是现在写的jdbc代码), 数据库服务器(存储数据的服务器)都是在一个主机上, 当然装在不同主机上就需要改变ip了.

再后面的3306是端口的意思, 一个主机上有很多个程序, 如果来识别是哪一个端口呢? 于是就有了端口的概念, 端口是用来区分应用程序的, 数据库的默认端口就是3306.

再后面的test2, 也就是我们的数据库名,如图 :

后面的characterEncoding=utf8 是表明数据库所使用的字符集为utf8.

后面的useSSL=false 是一个加密协议, 此处false, 也就是说不加密.

2.设置用户和密码

光有数据源还不够, 还需要设置用户名和用户密码:

public class JDBC {
    public static void main(String[] args){
        DataSource dataSource = new MysqlDataSource();
        // 创建数据源
        ((MysqlDataSource)dataSource).setUrl(
        "jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&useSSL=false"
        );
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("238638");
    }
}

只有设置了数据源, 用户名和密码才能访问数据库服务器:

使用setUser和setPassword. 其中用户名默认就是root, 这里只是设置了一遍但还是root.

setPassword是你安装数据库的时候设置的密码, 例如你数据库的密码是123456, 那么setPassword的参数就是123456(字符串形式).

这两步完成之后, 还没有对数据库进行连接, 那么如何连接?

3.连接数据库

使用DataSource中的getConnecttion()方法.

public class JDBC {
    public static void main(String[] args){
        DataSource dataSource = new MysqlDataSource();
        // 创建数据源
        ((MysqlDataSource)dataSource).setUrl(
        "jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&useSSL=false"
        );
        // 设置用户名
        ((MysqlDataSource)dataSource).setUser("root");
        // 输入数据库密码
        ((MysqlDataSource)dataSource).setPassword("238638");
        // 建立数据库连接
        datasource.getConnection();
    }
}

但是这样, getConnection()依然会报错, 如下:

这是一种受查异常, 所以我们应该在main方法上抛出此异常, 然后使用变量接收其返回值:

public class JDBCInsert {
    public static void main(String[] args) throws SQLException {
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("238638");
        Connection connection = dataSource.getConnection();
    }
}

注意此处的Connection接口为java.sql中的Connection接口, 而不是其他的接口.

如果服务器连接失败, 就抛出异常.

编写JDBC-SQL语句

在创建好数据源, 设置用户名和输入数据库密码, 连接数据库服务器之后, 就可以使用SQL语句进行增删改查的操作了.

以这个简单的表为例子:

create table student(age int, name varchar(20));

使用插入

String sql = "insert into student values(18,'张三');";
PreparedStatement statement = connection.prepareStatement(sql);

这个sql只是一个字符串的sql, 还不能被真正的执行. 所以还要进行预处理一下, 也就是下面的statement, 对我们的sql语句进行一个预编译:

PrepareStatement - > 提前预编译

这里的sql字符换服务器是可以处理的, 服务器首先需要对SQL进行解析, 理解这里的含义并执行, 但是如果客户端这里有几千万个sql字符串请求, 那么对于服务器来说压力就比较大.

编译构造完成之后, 就可以执行SQL语句了:

statement.executeUpdate();

int ret = statement.executeUpdate();
System.out.println("ret = "+ ret);

这一步操作将SQL语句发送给服务器.

对于executeUpdate是一个返回值为int 的方法, 表示你影响到的行数, 除了insert, 后面的delete和update都是用的executeUpdate方法:

statement对象

Statement对象主要是将SQL语句发送到数据库中。JDBC API中主要提供了三种Statement对象

  1. Statement, 用于执行不带参数的简单SQL语句
  2. PreparedStatement, 用于执行带或者不带参数的SQL语句, SQL语句会预编译在数据库系统, 执行速度快于Statement对象
  3. CallableStatement, 用于执行数据库存储过程中的调用

释放资源

数据库的服务器和客户端, 之间进行通信的时候会消耗一定的系统资源的, 包含:cpu, 内存, 硬盘, 带宽.....对于服务器来说同一时间要处理很多个客户端, 这个时候就产生了一个问题, 给一个客户端提供服务需要消耗一定的资源, 要是给10个, 或者更多的客户端提供服务, 那么就会消耗更多的资源.

怎么样才能节约或者更好地利用更多资源呢, 那么就得客户端尽量少使用资源, 不用的赶紧释放资源.

使用语句:

// 释放资源
statement.close();
connection.close();

完整代码:

public class JDBCInsert {
    public static void main(String[] args) throws SQLException {
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("238638");
        Connection connection = dataSource.getConnection();
 
        String sql = "insert into student values(18, '张三');";
        PreparedStatement statement = connection.prepareStatement(sql);
        int ret = statement.executeUpdate();
        System.out.println("ret = "+ ret);
    }
}

ResultSet对象(查询操作)

对于查询来说, 返回的结果就不是int这么简单了, 而是一个ResultSet对象 .

ResultSet对象被称为结果集, 它象征着数据库中的一个临时表的身份, 代表着符合SQL查询语句的所有行, 并且提供一套完整的get方法来对这些记录进行访问. ResultSet里面的数据是一行一行排列的, 每行有多个属性(字段), 并且有一个记录指针, 指向行首数据.

跟插入语句一样, 我们需要以下过程(除了第e步, 其他都类似):

  1. 创建数据源
  2. 建立连接
  3. 构造SQL语句
  4. 执行SQL语句
  5. 遍历结果集合
  6. 释放资源
public class JDBCSelect {
    public static void main(String[] args) throws SQLException {
        // 建立数据源
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root"); // 用户名(一般为root)
        ((MysqlDataSource)dataSource).setPassword("238638"); // 密码, 数据库初始密码
        // 建立连接 java.sql这个包
        Connection connection = dataSource.getConnection();
 
        // 编写SQL语句对象
        String sql = "select * from student;";
        // 预编译
        PreparedStatement statement = connection.prepareStatement(sql);
 
        // 遍历集合
        ResultSet resultSet = statement.executeQuery();
        while(resultSet.next()) {
            // 把resultSet想象成一个表格, 同时表里面有个光标, 初始情况下这个表的光标指向最上面一个记录
            // 每个next光标就会往下走一个记录
            int age = resultSet.getInt("age");
            String name = resultSet.getString("name");
            System.out.println("age = " + age + ", name = " + name);
        }
        // 释放资源
        statement.closs();
        connection.close();
        resultSet.close();
    }

查询到的这个临时表就是resultSet

硬编码

要插入的数据是写死的, 这样的操作成为硬编码. 这种方式就很不合适, 更合适的做法是, 把数据通过其他的方式让用户输入:

public class JDBCInsert {
    public static void main(String[] args) throws SQLException {
        Scanner scanner = new Scanner(System.in);
 
        // 创建数据源
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
 
        // 设置用户名, 输入数据库密码(都是以字符串为参数)
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("238638");
 
        // 连接数据库服务器
        Connection connection = dataSource.getConnection();
        System.out.println("请输入姓名:>");
        String name = scanner.next();
        System.out.println("请输入年龄:>");
        int age = scanner.nextInt();
        // 输入SQL语句
        String sql = "insert into student values(" + age + ", ' "+ name+ "');";
 
        // 预编译SQL语句, 减少数据库服务器负担
        PreparedStatement statement = connection.prepareStatement(sql);
 
        // 执行SQL语句并接收返回值
        int ret = statement.executeUpdate();
        System.out.println("ret = "+ ret);
    }
}

但是这只是一种下策, 虽然确实可以让用户动态输入. 但是这种输入的代码非常的丑陋膈应, 比如这个字符串拼接, 非常容易写错, 而且可读性很差.不推荐, 还可能带来一个风险,也就是SQL注入, 这是网络安全中典型的攻击方式. 而且这样写, 非常的麻烦.

所以我们可以使用占位符 ? 的形式来进行自由插入数据:

public class JDBCInsert {
    public static void main(String[] args) throws SQLException {
        Scanner scanner = new Scanner(System.in);
 
        // 创建数据源
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
 
        // 设置用户名, 输入数据库密码
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("238638");
 
        // 连接数据库服务器
        Connection connection = dataSource.getConnection();
        System.out.println("请输入姓名:>");
        String name = scanner.next();
        System.out.println("请输入年龄:>");
        int age = scanner.nextInt();
        // 输入SQL语句
        String sql = "insert into student values(?, ?);";
        // 预编译SQL语句, 减少数据库服务器负担
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setInt(1, id);
        statement.setString(2, name);
        // 执行SQL语句并接收返回值
        int ret = statement.executeUpdate();
        System.out.println("ret = "+ ret);
    }
}

使用 :

String name = scanner.next();
int age = scanner.nextInt();
String sql = "insert into student values(?, ?);";
        // 预编译SQL语句, 减少数据库服务器负担
PreparedStatement statement = connection.prepareStatement(sql);
statement.setInt(1, id);
statement.setString(2, name);

此时可以对statement进行打印:使用System.out.print(statement);

后面就是拼装好的SQL语句. 如果你的插入语句出错了, 你就可以把你的写的SQL语句打印出来, 然后就可以从这里看出来哪里有语法问题. 或者是直接将其拷贝到SQL控制台去操作.

以上只是给出了int和varchar类型数据的插入. 类似的还有DATETIME, Long等类型:

DriverManager

除了DataSource这种写法, 还有一种写法为DriverManager, DriverManager是通过反射的方法来加载驱动包中的类, 进一步进行后续的SQL语句等相关操作.

反射属于java的特殊手段, 相当于伤敌一千, 自损八百的那种类型, 其代码的可读性非常差, 编译器难以对代码的正确性进行验证和检查, 非常容易在运行的时候产生异常. 所以在使用上更推荐DataSource.

而DataSource类内置了数据库连接池, 可以复位连接, 提高服务器的效率.

那什么是数据库连接池呢? 可以类比于字符串常量池, 池(pool) 是计算机中使用非常广泛的专业术语, 本质上就是对资源进行 预申请, 就相当于使用空间换时间,

总结

  1. 什么是数据库API
  2. 什么是数据库JDBC编程
  3. 如何导入数据库(包含数据库驱动包的下载)
  4. 编写代码
  5. 创建数据源, 描述数据库服务器的位置
  6. 和服务器建立连接
  7. 构造SQL语句
  8. 执行SQL语句
  9. 释放资源
  10. 新的类和方法
  11. DataSource, 描述数据源
  12. Connection, 和数据库服务器建立连接(由数据源建立)
  13. PreparedStatement, 对SQL语句进行一个预编译, 让数据库服务器减轻相关负担
  14. ResultSet, 查询操作的结果集合, 使用while和next来遍历
  15. 硬编码: 方便书写
  16. 为什么要对资源进行释放


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
27天前
|
Java 程序员 应用服务中间件
【高薪程序员必看】万字长文拆解Java并发编程!(2 2-2)
📌 核心痛点暴击:1️⃣ 面了8家都被问synchronized锁升级?一张图看懂偏向锁→重量级锁全过程!2️⃣ 线程池参数不会配?高并发场景下这些参数调优救了项目组命!3️⃣ volatile双重检测单例模式到底安不安全?99%人踩过的内存可见性大坑!💡 独家亮点抢先看:✅ 图解JVM内存模型(JMM)三大特性,看完再也不怕指令重排序✅ 手撕ReentrantLock源码,AQS队列同步器实现原理大揭秘✅ 全网最细线程状态转换图(附6种状态转换触发条件表)
48 0
|
9天前
|
Java 数据库连接 API
2025 更新必看:Java 编程基础入门级超级完整版指南
本教程为2025更新版Java编程基础入门指南,涵盖开发环境搭建(SDKMAN!管理JDK、VS Code配置)、Java 17+新特性(文本块、Switch表达式增强、Record类)、面向对象编程(接口默认方法、抽象类与模板方法)、集合框架深度应用(Stream API高级操作、并发集合)、模式匹配与密封类等。还包括学生成绩管理系统实战项目,涉及Maven构建、Lombok简化代码、JDBC数据库操作及JavaFX界面开发。同时提供JUnit测试、日志框架使用技巧及进阶学习资源推荐,助你掌握Java核心技术并迈向高级开发。
72 5
|
15天前
|
JavaScript 前端开发 Java
Java 编程进阶实操中工具集整合组件封装方法与使用指南详解
本文详细介绍Hutool工具集和图书管理系统相关组件的封装方法及使用示例。通过通用工具类封装(如日期格式化、字符串处理、加密等)、数据库操作封装(结合Hutool DbUtil与MyBatis)、前端Vue组件封装(图书列表与借阅表单)以及后端服务层封装(业务逻辑实现与REST API设计),帮助开发者提升代码复用性与可维护性。同时,提供最佳实践建议,如单一职责原则、高内聚低耦合、参数配置化等,助力高效开发。适用于Java编程进阶学习与实际项目应用。
83 10
|
9天前
|
Oracle Java 关系型数据库
java 编程基础入门级超级完整版教程详解
这份文档是针对Java编程入门学习者的超级完整版教程,涵盖了从环境搭建到实际项目应用的全方位内容。首先介绍了Java的基本概念与开发环境配置方法,随后深入讲解了基础语法、控制流程、面向对象编程的核心思想,并配以具体代码示例。接着探讨了常用类库与API的应用,如字符串操作、集合框架及文件处理等。最后通过一个学生成绩管理系统的实例,帮助读者将理论知识应用于实践。此外,还提供了进阶学习建议,引导学员逐步掌握更复杂的Java技术。适合初学者系统性学习Java编程。资源地址:[点击访问](https://pan.quark.cn/s/14fcf913bae6)。
56 2
|
15天前
|
前端开发 Java 数据库连接
Java 编程进阶实操之工具集整合应用指南
本文聚焦Java编程进阶实操,涵盖并发编程、性能优化及数据库操作优化等核心知识点,并结合Hutool、Postman、Git等实用工具,提供从理论到实践的学习路径。通过小型图书管理系统实战项目,详细解析技术选型与实现步骤,助力开发者掌握Spring Boot、MyBatis等框架应用。同时展望Java新特性与技术趋势,为职业发展奠定基础。资源链接:[点此获取](https://pan.quark.cn/s/14fcf913bae6)。
49 1
|
25天前
|
Java 开发者
Java编程实用技巧:提升代码质量与开发效率
Java作为一门成熟且广泛应用的编程语言,掌握一些实用技巧可以显著提高开发效率和代码质量。以下是值得Java开发者掌握的实用技巧:
42 6
|
10天前
|
人工智能 Java API
Java并发编程之Future与FutureTask
本文深入解析了Future接口及其实现类FutureTask的原理与使用。Future接口定义了获取任务结果、取消任务及查询任务状态的规范,而FutureTask作为其核心实现类,结合了Runnable与Future的功能。文章通过分析FutureTask的成员变量、状态流转、关键方法(如run、set、get、cancel等)的源码,展示了异步任务的执行与结果处理机制。最后,通过示例代码演示了FutureTask的简单用法,帮助读者更直观地理解其工作原理。适合希望深入了解Java异步编程机制的开发者阅读。
|
27天前
|
网络协议 Java 大数据
【高薪程序员必看】万字长文拆解Java并发编程!(1)
📌 核心痛点暴击:1️⃣ 面了8家都被问synchronized锁升级?一张图看懂偏向锁→重量级锁全过程!2️⃣ 线程池参数不会配?高并发场景下这些参数调优救了项目组命!3️⃣ volatile双重检测单例模式到底安不安全?99%人踩过的内存可见性大坑!💡 独家亮点抢先看:✅ 图解JVM内存模型(JMM)三大特性,看完再也不怕指令重排序✅ 手撕ReentrantLock源码,AQS队列同步器实现原理大揭秘✅ 全网最细线程状态转换图(附6种状态转换触发条件表)
45 0
|
27天前
|
安全 Java 程序员
【高薪程序员必看】万字长文拆解Java并发编程!(2 2-1)
🔥【高薪程序员必看】万字长文拆解Java并发编程!面试官看了直呼内行,90%人不知道的线程安全骚操作!💻🚀《16个高频面试灵魂拷问+底层源码暴击》🔥👉戳这里看如何用1个月经验吊打3年程序员!📌 核心痛点暴击:1️⃣ 面了8家都被问synchronized锁升级?一张图看懂偏向锁→重量级锁全过程!2️⃣ 线程池参数不会配?高并发场景下这些参数调优救了项目组命!3️⃣ volatile双重检测单例模式到底安不安全?99%人踩过的内存可见性大坑!
36 0
|
27天前
|
缓存 安全 Java
【高薪程序员必看】万字长文拆解Java并发编程!(3-1):并发共享问题的解决与分析
活锁:多个线程相互影响对方退出同步代码块的条件而导致线程一直运行的情况。例如,线程1的退出条件是count=5,而线程2和线程3在其代码块中不断地是count进行自增自减的操作,导致线程1永远运行。内存一致性问题:由于JIT即时编译器对缓存的优化和指令重排等造成的内存可见性和有序性问题,可以通过synchronized,volatile,并发集合类等机制来解决。这里的线程安全是指,多个线程调用它们同一个实例的方法时,是线程安全的,但仅仅能保证当前调用的方法是线程安全的,不同方法之间是线程不安全的。
33 0