多线程有使用过吗?
用过,使用多线程,要保证多线程是安全的,不要出现数据竞争,造成数据混乱的问题
Java的线程安全体现在三个方面:
-
原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作
- 在Java中,使用了
atomic类
和synchronized
这个关键字,来确保原子性
- 在Java中,使用了
-
可见性:一个线程对主内存的修改可以及时地被其他线程看到
- 在Java中,使用了
synchronized
和volatile
这两个关键字,确保可见性
- 在Java中,使用了
-
有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序
- 在Java中使用了
happens-before
原则,来确保有序性
- 在Java中使用了
在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();
}
}
总结:
- 减少同步范围
- 使用更细粒度的锁
- 使用读写锁
- 使用原子类或CAS操作