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操作
相关推荐
短剑重铸之日44 分钟前
《ShardingSphere解读》07 读写分离:如何集成分库分表+数据库主从架构?
java·数据库·后端·架构·shardingsphere·分库分表
wefly20172 小时前
m3u8live.cn 在线M3U8播放器,免安装高效验流排错
前端·后端·python·音视频·前端开发工具
zhanggongzichu3 小时前
小白怎么理解后端分层概念
后端·全栈
stark张宇3 小时前
Golang后端面试复盘:从Swoole到IM架构,如何支撑360w用户的实时消息推送?
后端
小码哥_常4 小时前
从0到1:搭建Spring Boot 3企业级认证授权平台
后端
敲代码的嘎仔4 小时前
Java后端面试——SSM框架面试题
java·面试·职场和发展·mybatis·ssm·springboot·八股
小码哥_常4 小时前
告别扫库噩梦!Spring Boot+Redis让订单超时管理飞起来
后端
大傻^4 小时前
Spring AI Alibaba 快速入门:基于通义千问的AI应用开发环境搭建
java·人工智能·后端·spring·springai·springaialibaba
IT_陈寒5 小时前
SpringBoot实战:3个隐藏技巧让你的应用性能飙升50%
前端·人工智能·后端
彭于晏Yan5 小时前
MQTT消息服务
spring boot·后端·中间件