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

java面试题,有synchronized锁,threadlocal、数据可以设置默认值、把redis中的json转为对象

有面试题,有synchronized锁,threadlocal

  • 一、面试题小记
  • 二、加锁synchronized
    • 1. 先看代码
    • 2. synchronized 讲解
      • 2.1. 同步代码块
      • 2.2. 同步方法
      • 2.3. 锁的选择和影响
      • 2.4. 注意事项
      • 2.5 锁的操作,手动释放锁,显式地获取锁(属性名第一个lock代表的是)
  • 三、ThreadLocal
    • 1. 基本用法
    • 2. ThreadLocal 的关键方法
    • 3. 使用场景
    • 4. 注意事项
    • 5. 示例:使用 ThreadLocal 进行数据库连接管理
  • 四、数据库用来设置某个字段的默认值。
  • 五、 把redis的json转为对象
    • 1. 从 Redis 获取 JSON 数据
    • 2 使用 Gson

(一切都是自己的笔记!!!请勿上纲上线)

一、面试题小记

在这里插入图片描述
在这里插入图片描述
java10 本地类型推断
在这里插入图片描述
switch表达式
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、加锁synchronized

1. 先看代码

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.HashSet;public class Example {private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");private static final Set<String> dates = new HashSet<>();private static final CountDownLatch countDownLatch = new CountDownLatch(10);private static final ExecutorService pool = Executors.newFixedThreadPool(10);public void addDate(int i) {Calendar calendar = Calendar.getInstance(); // 创建Calendar实例int finalI = i; // final变量用于在lambda表达式中使用pool.execute(() -> {synchronized (simpleDateFormat) { // 对simpleDateFormat加锁// 时间增加calendar.add(Calendar.DATE, finalI);// 通过simpleDateFormat把时间转换成字符串String dateString = simpleDateFormat.format(calendar.getTime());// 把字符串放入Set中dates.add(dateString);}// CountDowncountDownLatch.countDown();});}public void awaitCompletion() throws InterruptedException {countDownLatch.await(); // 等待所有线程完成pool.shutdown(); // 关闭线程池}public static void main(String[] args) throws InterruptedException {Example example = new Example();for (int i = 0; i < 10; i++) {example.addDate(i); // 添加日期}example.awaitCompletion(); // 等待所有线程完成System.out.println(dates); // 输出结果}
}

2. synchronized 讲解

synchronized 是 Java 中用于实现线程同步的关键字,确保多个线程在执行某段代码时不会发生冲突,从而保证线程安全。它有两种主要的使用方式:同步代码块和同步方法。

2.1. 同步代码块

通过 synchronized 关键字修饰的代码块可以确保在同一时间只有一个线程可以执行该代码块中的代码。以下是如何使用同步代码块的示例:

public class SynchronizedBlockExample {private final Object lock = new Object(); // 用于锁定的对象public void doWork() {synchronized (lock) { // 对 lock 对象加锁// 临界区代码System.out.println("Thread " + Thread.currentThread().getName() + " is working.");} // 离开synchronized块时自动释放锁}
}

锁定对象:synchronized (lock) 表示对 lock 对象加锁。只有获取了 lock 锁的线程可以执行 synchronized 块中的代码。
自动释放:当线程退出 synchronized 块(包括发生异常的情况),JVM 会自动释放锁。

2.2. 同步方法

synchronized 也可以用于修饰方法,这样整个方法在同一时间只会被一个线程执行。同步方法可以分为实例方法和静态方法:

实例同步方法:锁定的是方法所在对象的实例。

public class SynchronizedMethodExample {public synchronized void instanceMethod() {// 临界区代码System.out.println("Thread " + Thread.currentThread().getName() + " is working.");}
}

静态同步方法:锁定的是类的 Class 对象。静态同步方法同一时间只允许一个线程访问类的所有实例的静态方法。

public class SynchronizedStaticMethodExample {public static synchronized void staticMethod() {// 临界区代码System.out.println("Thread " + Thread.currentThread().getName() + " is working.");}
}

2.3. 锁的选择和影响

对象锁:在同步代码块中指定的对象(例如 lock 对象)会作为锁对象。这种锁是对象级别的,不同对象的同步代码块不会互相影响。

类锁:对于静态同步方法,锁的是类的 Class 对象。这意味着类的所有静态同步方法是互斥的。

锁的粒度:选择锁的粒度时需要考虑性能和安全。粒度过大(例如锁住整个方法或类)可能导致性能下降,而粒度过小则可能无法有效防止数据竞争。

2.4. 注意事项

死锁:多个线程可能互相等待对方释放锁,导致系统僵死。应避免复杂的锁定顺序和嵌套锁。

性能开销:同步会引入性能开销,因为它涉及到线程上下文的切换和锁管理。只在必要时使用同步,尽量减少锁的持有时间。

不可重入:虽然 synchronized 是可重入的(即同一个线程可以多次获取同一个锁),但在设计时仍需注意避免复杂的锁定结构。

总结
同步代码块:通过 synchronized (lock) 对特定的对象进行加锁,确保只有一个线程能执行代码块中的代码。
同步方法:通过 synchronized 关键字修饰实例方法或静态方法,确保方法在同一时间内只有一个线程能执行。

2.5 锁的操作,手动释放锁,显式地获取锁(属性名第一个lock代表的是)

lock.lock():显式地获取锁。
lock.unlock():在 finally 块中释放锁,以确保即使发生异常也能释放锁。

三、ThreadLocal

ThreadLocal 是 Java 中用于实现线程局部存储的类,允许每个线程在访问某个变量时拥有自己的独立副本。这样,每个线程都可以操作自己的副本而不会与其他线程的副本发生冲突。ThreadLocal 主要用于需要线程隔离的场景,例如每个线程需要独立的配置、数据库连接、会话等。

1. 基本用法

ThreadLocal 的基本用法非常简单。可以通过 ThreadLocal 提供的 get 和 set 方法来获取和设置当前线程的值。

public class ThreadLocalExample {private static final ThreadLocal<Integer> threadLocalValue = ThreadLocal.withInitial(() -> 1);public static void main(String[] args) {Runnable task = () -> {// 获取当前线程的线程局部变量值Integer value = threadLocalValue.get();System.out.println("Initial Value: " + value);// 设置当前线程的线程局部变量值threadLocalValue.set(value + 1);// 再次获取当前线程的线程局部变量值System.out.println("Updated Value: " + threadLocalValue.get());};// 创建多个线程,测试每个线程的线程局部变量是否独立Thread thread1 = new Thread(task);Thread thread2 = new Thread(task);thread1.start();thread2.start();}
}

2. ThreadLocal 的关键方法

ThreadLocal.withInitial(Supplier<? extends T> supplier):创建一个 ThreadLocal 实例,并设置初始值。这个方法可以指定一个 Supplier 来提供初始值。

T get():获取当前线程的 ThreadLocal 变量的值。如果当前线程没有设置过这个值,则会调用 initialValue() 方法来设置初始值。

void set(T value):设置当前线程的 ThreadLocal 变量的值。

void remove():移除当前线程的 ThreadLocal 变量的值,防止内存泄漏。

3. 使用场景

ThreadLocal 主要适用于以下场景:

数据库连接:每个线程需要一个独立的数据库连接。

用户会话:每个线程需要维护独立的用户会话信息。

配置和上下文:每个线程需要独立的配置或上下文信息。

4. 注意事项

内存泄漏:如果 ThreadLocal 的 ThreadLocalMap 中的 ThreadLocal 引用被持有而没有被正确清理(通过调用 remove() 方法),可能会导致内存泄漏,特别是在长期运行的应用中。由于 ThreadLocal 是线程本地的,它的值只会在当前线程中有效,所以如果线程池中线程长时间存在而没有被回收,就可能导致内存泄漏。

适用性:ThreadLocal 适用于线程独立的场景。如果不同线程之间需要共享数据,考虑使用其他同步机制(如 synchronized 或 Concurrent 数据结构)。

性能:虽然 ThreadLocal 提供了线程隔离,但它也有一定的性能开销。避免在高并发场景中频繁使用 ThreadLocal,特别是当线程局部变量对象较大或线程较多时。

5. 示例:使用 ThreadLocal 进行数据库连接管理

public class DatabaseConnectionManager {private static final ThreadLocal<Connection> connectionHolder = ThreadLocal.withInitial(() -> {try {return DriverManager.getConnection("jdbc:yourdb", "username", "password");} catch (SQLException e) {throw new RuntimeException(e);}});public static Connection getConnection() {return connectionHolder.get();}public static void closeConnection() {Connection connection = connectionHolder.get();if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();} finally {connectionHolder.remove(); // 清理线程局部变量}}}
}

在这个示例中,每个线程会有自己独立的数据库连接,使用完后记得调用 remove() 方法以避免潜在的内存泄漏。

四、数据库用来设置某个字段的默认值。

ALTER TABLE in_inspect_info
ALTER result SET DEFAULT 1;

五、 把redis的json转为对象

从 Redis 中获取 JSON 数据并将其转换为 Java 对象,通常涉及以下几个步骤:

从 Redis 获取 JSON 数据: 你可以使用 Redis 客户端库(例如 Jedis 或 Lettuce)从 Redis 中获取存储的 JSON 数据。
将 JSON 转换为 Java 对象: 使用 JSON 解析库(如 Jackson 或 Gson)将 JSON 字符串转换为 Java 对象。
以下是详细的步骤和代码示例:

1. 从 Redis 获取 JSON 数据

假设你使用 Jedis 作为 Redis 客户端库,首先从 Redis 中获取 JSON 数据:

import redis.clients.jedis.Jedis;public class RedisExample {public static void main(String[] args) {// 创建 Jedis 实例Jedis jedis = new Jedis("localhost", 6379);// 从 Redis 中获取 JSON 数据String jsonData = jedis.get("yourRedisKey");// 关闭 Jedis 连接jedis.close();// 打印获取到的 JSON 数据System.out.println(jsonData);}
}
  1. 将 JSON 转换为 Java 对象
    使用 Jackson 或 Gson 库将 JSON 字符串转换为 Java 对象。以下是使用 Jackson 和 Gson 的示例。

使用 Jackson
添加依赖(如果你使用 Maven,可以在 pom.xml 中添加以下依赖):

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.14.2</version>
</dependency>

转换 JSON:

import com.fasterxml.jackson.databind.ObjectMapper;public class JsonExample {public static void main(String[] args) {String jsonData = "{\"term_sn\":\"12345\",\"devid_qi_cname\":\"设备名称\",\"devid_qi_time\":\"2024-07-22T10:00:00Z\",\"inspect_list\":[{\"code\":\"INS001\",\"name\":\"检查1\",\"term_sn\":\"TERM001\",\"inspect_ask\":\"检查要求1\",\"result\":\"结果1\"},{\"code\":\"INS002\",\"name\":\"检查2\",\"term_sn\":\"TERM002\",\"inspect_ask\":\"检查要求2\",\"result\":\"结果2\"}],\"dq_info_file_ids\":98765,\"devidqi_state\":1}";ObjectMapper objectMapper = new ObjectMapper();try {// 将 JSON 转换为 Java 对象MyClass myObject = objectMapper.readValue(jsonData, MyClass.class);// 打印转换后的对象System.out.println(myObject);} catch (Exception e) {e.printStackTrace();}}
}class MyClass {private String term_sn;private String devid_qi_cname;private String devid_qi_time;private List<Inspect> inspect_list;private int dq_info_file_ids;private int devidqi_state;// Getter 和 Setter 方法@Overridepublic String toString() {return "MyClass{" +"term_sn='" + term_sn + '\'' +", devid_qi_cname='" + devid_qi_cname + '\'' +", devid_qi_time='" + devid_qi_time + '\'' +", inspect_list=" + inspect_list +", dq_info_file_ids=" + dq_info_file_ids +", devidqi_state=" + devidqi_state +'}';}
}class Inspect {private String code;private String name;private String term_sn;private String inspect_ask;private String result;// Getter 和 Setter 方法@Overridepublic String toString() {return "Inspect{" +"code='" + code + '\'' +", name='" + name + '\'' +", term_sn='" + term_sn + '\'' +", inspect_ask='" + inspect_ask + '\'' +", result='" + result + '\'' +'}';}
}

2 使用 Gson

添加赖(如果你使用 Maven,可以在 pom.xml 中添加以下依赖):

<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.10.1</version>
</dependency>

转换 JSON:

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;public class JsonExample {public static void main(String[] args) {String jsonData = "{\"term_sn\":\"12345\",\"devid_qi_cname\":\"设备名称\",\"devid_qi_time\":\"2024-07-22T10:00:00Z\",\"inspect_list\":[{\"code\":\"INS001\",\"name\":\"检查1\",\"term_sn\":\"TERM001\",\"inspect_ask\":\"检查要求1\",\"result\":\"结果1\"},{\"code\":\"INS002\",\"name\":\"检查2\",\"term_sn\":\"TERM002\",\"inspect_ask\":\"检查要求2\",\"result\":\"结果2\"}],\"dq_info_file_ids\":98765,\"devidqi_state\":1}";Gson gson = new Gson();// 将 JSON 转换为 Java 对象MyClass myObject = gson.fromJson(jsonData, MyClass.class);// 打印转换后的对象System.out.println(myObject);}
}class MyClass {private String term_sn;private String devid_qi_cname;private String devid_qi_time;private List<Inspect> inspect_list;private int dq_info_file_ids;private int devidqi_state;// Getter 和 Setter 方法@Overridepublic String toString() {return "MyClass{" +"term_sn='" + term_sn + '\'' +", devid_qi_cname='" + devid_qi_cname + '\'' +", devid_qi_time='" + devid_qi_time + '\'' +", inspect_list=" + inspect_list +", dq_info_file_ids=" + dq_info_file_ids +", devidqi_state=" + devidqi_state +'}';}
}class Inspect {private String code;private String name;private String term_sn;private String inspect_ask;private String result;// Getter 和 Setter 方法@Overridepublic String toString() {return "Inspect{" +"code='" + code + '\'' +", name='" + name + '\'' +", term_sn='" + term_sn + '\'' +", inspect_ask='" + inspect_ask + '\'' +", result='" + result + '\'' +'}';}
}

关键点总结
选择合适的库: Jackson 和 Gson 都是流行的 JSON 解析库,可以根据你的需求选择其中一个。
确保字段匹配: JSON 字段名称应与 Java 类中的字段名称匹配,注意大小写和命名风格。
处理日期: 如果 JSON 中包含日期,确保正确解析和格式化日期字段。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 使用内网穿透工具 frp 发布内网 web 站点
  • WebGoC题解(13) 狐猬编程:GoC L4 结业测试 第4题 找木柴
  • 自动驾驶---视觉Transformer的应用
  • 工具(linux)
  • 判断用户输入IP的合法性判断输入IP与本机IP是否在同一网段C++QT
  • 【中项】系统集成项目管理工程师-第4章 信息系统架构-4.3应用架构
  • (7) cmake 编译C++程序(二)
  • PyTorch 深度学习实践-循环神经网络(高级篇)
  • React--Redux
  • 多维时序 | Transformer+BiLSTM多变量时间序列预测(Python)
  • HAL库源码移植与使用之RTC时钟
  • 时间和空间复杂度
  • Docker、containerd、CRI-O 和 runc 之间的区别
  • 第1关 -- Linux 基础知识
  • AV1技术学习:Transform Coding
  • 【EOS】Cleos基础
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • input的行数自动增减
  • Lucene解析 - 基本概念
  • NLPIR语义挖掘平台推动行业大数据应用服务
  • npx命令介绍
  • orm2 中文文档 3.1 模型属性
  • Python进阶细节
  • Spark学习笔记之相关记录
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • 对象管理器(defineProperty)学习笔记
  • 构造函数(constructor)与原型链(prototype)关系
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 前端学习笔记之观察者模式
  • 前端之Sass/Scss实战笔记
  • 阿里云ACE认证之理解CDN技术
  • !$boo在php中什么意思,php前戏
  • $.ajax()方法详解
  • (06)Hive——正则表达式
  • (13)Hive调优——动态分区导致的小文件问题
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (附源码)springboot课程在线考试系统 毕业设计 655127
  • (每日持续更新)jdk api之FileFilter基础、应用、实战
  • (七)Appdesigner-初步入门及常用组件的使用方法说明
  • (转)ABI是什么
  • (转)linux 命令大全
  • .ai域名是什么后缀?
  • .bat文件调用java类的main方法
  • .Net 6.0--通用帮助类--FileHelper
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .net 写了一个支持重试、熔断和超时策略的 HttpClient 实例池
  • .NET 中使用 Mutex 进行跨越进程边界的同步
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)
  • .netcore 获取appsettings
  • .NET程序集编辑器/调试器 dnSpy 使用介绍
  • .Net开发笔记(二十)创建一个需要授权的第三方组件
  • .so文件(linux系统)