MST

星途 面试题库

面试题:Java多线程Socket编程中的线程安全问题

在Java多线程Socket编程场景下,多个线程可能同时访问和修改共享资源,列举至少两种可能导致线程安全问题的场景,并说明如何使用Java的同步机制(如synchronized关键字、Lock接口等)来解决这些问题。
27.9万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

可能导致线程安全问题的场景

  1. 资源竞争:多个线程同时尝试读取和修改同一个共享的Socket连接状态(如连接是否已建立、当前传输的数据位置等)。例如,一个线程准备发送数据时,另一个线程却在关闭连接,这可能导致数据丢失或连接异常。
  2. 数据不一致:当多个线程对共享的缓冲区(用于Socket数据收发)进行读写操作时,可能出现一个线程读取到不完整或不一致的数据。比如,一个线程正在向缓冲区写入数据,还未写完,另一个线程就开始从缓冲区读取,导致读取到错误的数据。

解决方法

  1. 使用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;
    }
}
  1. 使用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();
        }
    }
}
  • 处理Socket数据收发缓冲区:
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;
    }
}