Java多线程(每天两道面试题)

多线程有使用过吗?

用过,使用多线程,要保证多线程是安全的,不要出现数据竞争,造成数据混乱的问题

Java的线程安全体现在三个方面:

  • 原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作

    • 在Java中,使用了 atomic类synchronized 这个关键字,来确保原子性
  • 可见性:一个线程对主内存的修改可以及时地被其他线程看到

    • 在Java中,使用了synchronizedvolatile 这两个关键字,确保可见性
  • 有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序

    • 在Java中使用了 happens-before 原则,来确保有序性

在Synchronized的代码中怎么提高速度?

synchronized 是保证线程安全的重要机制,但它会带来性能开销

以下是提高 synchronized 代码块性能的几种方法:

  • 减少同步范围:尽量缩小 synchronized 代码块的范围,只对必要的代码进行同步,减少线程阻塞的时间
Java 复制代码
// 不推荐 - 同步整个方法  
public synchronized void process() {  
    // 大量不需要同步的代码  
    // ...  
    // 少量需要同步的代码  
}  
  
// 推荐 - 只同步关键部分  
public void process() {  
    // 不需要同步的代码  
    // ...  
    synchronized(this) {  
        // 需要同步的少量代码  
    }  
}
  • 使用更细粒度的锁:若有多个独立的资源需要同步,可使用多个不同的锁,而非一个全局锁,以此降低锁的竞争
Java 复制代码
// 不推荐 - 所有操作共用同一把锁  
privatefinal Object lock = new Object();  
  
public void updateA() {  
    synchronized(lock) { /* 操作A */ }  
}  
  
public void updateB() {  
    synchronized(lock) { /* 操作B */ }  
}  
  
// 推荐 - 不同操作使用不同的锁  
privatefinal Object lockA = new Object();  
privatefinal Object lockB = new Object();  
  
public void updateA() {  
    synchronized(lockA) { /* 操作A */ }  
}  
  
public void updateB() {  
    synchronized(lockB) { /* 操作B */ }  
}
  • 使用读写锁:若对共享资源的读操作远多于写操作,可使用 ReadWriteLock 来提高并发性能
    • 读锁可以被多个线程同时持有,而写锁是排他的
Java 复制代码
import java.util.concurrent.locks.ReadWriteLock;  
import java.util.concurrent.locks.ReentrantReadWriteLock;  
  
privatefinal ReadWriteLock rwLock = new ReentrantReadWriteLock();  
  
public void readOperation() {  
    rwLock.readLock().lock();  
    try {  
        // 读操作  
    } finally {  
        rwLock.readLock().unlock();  
    }  
}  
  
public void writeOperation() {  
    rwLock.writeLock().lock();  
    try {  
        // 写操作  
    } finally {  
        rwLock.writeLock().unlock();  
    }  
}
  • 使用原子类:对于一些简单的操作,如计数、递增等,可以使用 Java 的原子类(如 AtomicInteger),使用 CAS(Compare-And-Swap)操作,避免了使用 synchronized 带来的锁竞争
Java 复制代码
import java.util.concurrent.atomic.AtomicInteger;  
  
public class AtomicExample {  
    private AtomicInteger count = new AtomicInteger(0);  
  
    public void increment() {  
        count.incrementAndGet();  
    }  
  
    public int getCount() {  
        return count.get();  
    }  
}

总结:

  1. 减少同步范围
  2. 使用更细粒度的锁
  3. 使用读写锁
  4. 使用原子类或CAS操作
相关推荐
声声codeGrandMaster23 分钟前
Django框架的前端部分使用Ajax请求一
前端·后端·python·ajax·django
duapple6 小时前
Golang基于反射的ioctl实现
开发语言·后端·golang
my_styles9 小时前
docker-compose部署项目(springboot服务)以及基础环境(mysql、redis等)ruoyi-ry
spring boot·redis·后端·mysql·spring cloud·docker·容器
冬瓜的编程笔记10 小时前
【八股战神篇】MySQL高频面试题
数据库·mysql·面试
独行soc11 小时前
2025年渗透测试面试题总结-百度面经(题目+回答)
运维·开发语言·经验分享·学习·面试·渗透测试·php
免檒11 小时前
go语言协程调度器 GPM 模型
开发语言·后端·golang
不知道写什么的作者11 小时前
Flask快速入门和问答项目源码
后端·python·flask
caihuayuan512 小时前
生产模式下react项目报错minified react error #130的问题
java·大数据·spring boot·后端·课程设计
一只码代码的章鱼12 小时前
Spring Boot- 2 (数万字入门教程 ):数据交互篇
spring boot·后端·交互
编程、小哥哥12 小时前
Java大厂面试:从Web框架到微服务技术的场景化提问与解析
java·spring boot·微服务·面试·技术栈·数据库设计·分布式系统