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操作
相关推荐
Real_man8 分钟前
新物种与新法则:AI重塑开发与产品未来
前端·后端·面试
小马爱打代码37 分钟前
Spring Boot:将应用部署到Kubernetes的完整指南
spring boot·后端·kubernetes
卜锦元1 小时前
Go中使用wire进行统一依赖注入管理
开发语言·后端·golang
SoniaChen332 小时前
Rust基础-part3-函数
开发语言·后端·rust
全干engineer2 小时前
Flask 入门教程:用 Python 快速搭建你的第一个 Web 应用
后端·python·flask·web
没有bug.的程序员2 小时前
JAVA面试宝典 -《Spring Boot 自动配置魔法解密》
java·spring boot·面试
William一直在路上3 小时前
SpringBoot 拦截器和过滤器的区别
hive·spring boot·后端
小马爱打代码3 小时前
Spring Boot 3.4 :@Fallback 注解 - 让微服务容错更简单
spring boot·后端·微服务
旷世奇才李先生4 小时前
奇哥面试记:SpringBoot整合RabbitMQ与高级特性,一不小心吊打面试官
spring boot·面试·java-rabbitmq
mrsk4 小时前
🧙‍♂️ CSS中的结界术:BFC如何拯救你的布局混乱?
前端·css·面试