java java单例线程安全

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4965534/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 08:49:35  来源:igfitidea点击:

java singleton thread safe

javamultithreadingsingleton

提问by Willy

Ok, here is my problem.

好的,这是我的问题。

I need to create a socket program that can handle multiple connection from my client apps (lets call it apps1). I handle this using thread (so each connection was thrown into a new thread)

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

The problem is I can accept request from all open connection but when I want to send a response , I must send it through the latest connection only. So if I have 3 connections (con1,con2,con3) I can accept request from con1, con2 and con3 but I must send the response through con3 (assuming con3 is the latest connection)

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

I thought of using a singleton, with a PrintWriter parameter. So everytime there is a new connection ,they call the singleton and update the parameter and when I want to send the response, I get the PrintWriter first before sending.

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

Here is my Singleton class :

这是我的单例类:

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;
}
}

This is my main program :

这是我的主要程序:

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    
    } 
}

and this is my thread that handle socket :

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

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);
    }
}

Do I did it right? Or it is impossible to do it with singleton?

我做对了吗?或者用单例是不可能做到的?

Thanks for the help.

谢谢您的帮助。

回答by Tim Bender

Unfortunately, that is not a thread safe implementation of the Singleton pattern. I don't think you need one in this case either, an AtomicReferencewill probably work just fine. Try this:

不幸的是,这不是单例模式的线程安全实现。我认为在这种情况下您也不需要一个,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);
    }
}

If you really do want to use the Singleton pattern, here is a reference from SO where the question has a good thread-safe implementation for creating the Singleton: Java Singleton Pattern

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

You will also need to make accessing the Singleton's state thread-safe by using synchronized, Lock, or atomic operations (AtomicInteger, AtomicReference, etc..) as necessary.

你也将需要通过访问辛格尔顿的状态线程安全的synchronizedLock或者原子操作(AtomicIntegerAtomicReference,等)是必要的。