【问题标题】:java singleton thread safejava单例线程安全
【发布时间】:2011-02-11 12:51:11
【问题描述】:

好的,这是我的问题。

我需要创建一个套接字程序,它可以处理来自我的客户端应用程序的多个连接(我们称之为apps1)。我使用线程处理这个(所以每个连接都被扔到一个新线程中)

问题是我可以接受来自所有打开的连接的请求,但是当我想发送响应时,我必须只通过最新的连接发送它。因此,如果我有 3 个连接(con1、con2、con3),我可以接受来自 con1、con2 和 con3 的请求,但我必须通过 con3 发送响应(假设 con3 是最新连接)

我想过使用带有 PrintWriter 参数的单例。所以每次有新连接时,他们都会调用单例并更新参数,当我想发送响应时,我会在发送前先获取 PrintWriter。

这是我的单例类:

public class Singleton {

private static final Singleton instance = new Singleton();

PrintWriter  out;

public static Singleton getInstance() {
    return instance;
}
public Singleton ()
{
    if (instance != null) {
        throw new IllegalStateException("Already instantiated");
    }
}

public PrintWriter getPrintWriter ()
{
    return this.out;
}
public void updatePrintWriter (PrintWriter  out){
    this.out = out;
}
}

这是我的主程序:

public class SocketAccept{
private ServerSocket mainSocket;
private Socket clientSocket;

    public SocketAccept (int portNumber) {
        Singleton s = Singleton.getInstance();
        do {
        try {
            mainSocket = new ServerSocket(portNumber);
            clientSocket = mainSocket.accept();
            s.updatePrintWriter(new PrintWriter(clientSocket.getOutputStream(), true));
            ClientThread (clientSocket);
        } catch (IOException ex) {
            Logger.getLogger(TestClass.class.getName()).log(Level.SEVERE, null, ex);
        }
        }while (true);//need to change this into thread pool or connection pool    
    } 
}

这是我处理套接字的线程:

public class ClientThread extends Thread {

    private Socket cs;
    Singleton s = Singleton.getInstance();
    PrintWriter out;

    private String read(Socket sc) {
        String request = "";
        //read request here
        return request;
    }

    private String process(String request) {
        String response = "";
        //process request here
        return response;
    }

    public ClientThread(Socket clientSocket) {
        this.cs = clientSocket;
    }

    @Override
    public void run() {
        String requestMsg = "";
        String responseMsg = "";
        do {
            requestMsg = read(cs);// read the message

            if (requestMsg.equalsIgnoreCase("SHUTDOWN")) {
                break;
            }
            responseMsg = process(requestMsg);
            out = s.getPrintWriter();
            out.write(responseMsg);
        } while (true);
    }
}

我做对了吗?还是单例无法做到?

感谢您的帮助。

【问题讨论】:

  • 您能解释一下为什么所有打开的连接都必须始终只打印到最新的流吗?
  • 您想要一张海报来说明他们的要求吗?是不是有点傻?他并不是在问一个技术上不可行的问题。
  • @The Scrum Meister 如果可以的话,我通常会解释原因(因为如果你知道原因,有时会有另一种解决方案),遗憾的是客户要求它没有任何解释

标签: java multithreading singleton


【解决方案1】:

不幸的是,这不是单例模式的线程安全实现。我认为在这种情况下你也不需要一个,AtomicReference 可能会工作得很好。试试这个:

public class SocketAccept{
    private ServerSocket mainSocket;
    private Socket clientSocket;

    private final AtomicReference<PrintWriter> printWriterHolder = new AtomicReference(null);

    public SocketAccept (int portNumber) {
        Singleton s = Singleton.getInstance();
        do {
        try {
            mainSocket = new ServerSocket(portNumber);
            clientSocket = mainSocket.accept();
            printWriterHolder.set(new PrintWriter(clientSocket.getOutputStream(), true));
            Thread clientThread = new ClientThread (clientSocket, printWriterHolder);
            clientThread.start();
        } catch (IOException ex) {
            Logger.getLogger(TestClass.class.getName()).log(Level.SEVERE, null, ex);
        }
        }while (true);//need to change this into thread pool or connection pool    
    } 
}

...

public class ClientThread extends Thread
    ...
    private final AtomicReference<PrintWriter> printWriterHolder;
    public ClientThread(Socket clientSocket, AtomicReference<PrintWriter> holder) {
        this.cs = clientSocket;
        this.printWriterHolder = holder;
    }

    @Override
    public void run() {
        String requestMsg = "";
        String responseMsg = "";
        do {
            requestMsg = read(cs);// read the message

            if (requestMsg.equalsIgnoreCase("SHUTDOWN")) {
                break;
            }
            responseMsg = process(requestMsg);
            out = printWriterHolder.get();
            out.write(responseMsg);
        } while (true);
    }
}

如果你真的想使用单例模式,这里是来自 SO 的参考,其中问题有一个很好的线程安全实现来创建单例:Java Singleton Pattern

您还需要根据需要使用synchronizedLock 或原子操作(AtomicIntegerAtomicReference 等)使访问 Singleton 的状态线程安全。

【讨论】:

  • 哇,我不知道有没有使用 AtomicReference 的“简单”解决方案(这是我第一次读到它)。非常感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多