可能导致线程安全问题的场景
- 资源竞争:多个线程同时尝试读取和修改同一个共享的Socket连接状态(如连接是否已建立、当前传输的数据位置等)。例如,一个线程准备发送数据时,另一个线程却在关闭连接,这可能导致数据丢失或连接异常。
- 数据不一致:当多个线程对共享的缓冲区(用于Socket数据收发)进行读写操作时,可能出现一个线程读取到不完整或不一致的数据。比如,一个线程正在向缓冲区写入数据,还未写完,另一个线程就开始从缓冲区读取,导致读取到错误的数据。
解决方法
- 使用synchronized关键字
- 同步方法:将对共享资源操作的方法声明为
synchronized
。例如,如果有一个管理Socket连接状态的类:
public class SocketConnection {
private boolean isConnected = false;
public synchronized void connect() {
if (!isConnected) {
// 执行连接操作
isConnected = true;
}
}
public synchronized void disconnect() {
if (isConnected) {
// 执行断开连接操作
isConnected = false;
}
}
}
- 同步块:当需要对部分代码块进行同步时,使用
synchronized
块。假设在处理Socket数据收发的缓冲区:
public class SocketBuffer {
private byte[] buffer = new byte[1024];
private int position = 0;
public void write(byte[] data) {
synchronized (this) {
for (byte b : data) {
buffer[position++] = b;
}
}
}
public byte[] read(int length) {
byte[] result = new byte[length];
synchronized (this) {
for (int i = 0; i < length; i++) {
result[i] = buffer[position++];
}
}
return result;
}
}
- 使用Lock接口
- 以ReentrantLock为例,同样处理Socket连接状态:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SocketConnectionWithLock {
private boolean isConnected = false;
private Lock lock = new ReentrantLock();
public void connect() {
lock.lock();
try {
if (!isConnected) {
// 执行连接操作
isConnected = true;
}
} finally {
lock.unlock();
}
}
public void disconnect() {
lock.lock();
try {
if (isConnected) {
// 执行断开连接操作
isConnected = false;
}
} finally {
lock.unlock();
}
}
}
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SocketBufferWithLock {
private byte[] buffer = new byte[1024];
private int position = 0;
private Lock lock = new ReentrantLock();
private Condition notFull = lock.newCondition();
private Condition notEmpty = lock.newCondition();
public void write(byte[] data) throws InterruptedException {
lock.lock();
try {
while (position + data.length > buffer.length) {
notFull.await();
}
for (byte b : data) {
buffer[position++] = b;
}
notEmpty.signalAll();
} finally {
lock.unlock();
}
}
public byte[] read(int length) throws InterruptedException {
byte[] result = new byte[length];
lock.lock();
try {
while (position < length) {
notEmpty.await();
}
for (int i = 0; i < length; i++) {
result[i] = buffer[position++];
}
notFull.signalAll();
} finally {
lock.unlock();
}
return result;
}
}