首页 \ 问答 \ 多线程(无状态类)(Multithreading (Stateless Classes))

多线程(无状态类)(Multithreading (Stateless Classes))

为长代码发帖道歉,但我想知道是否有人可以帮助解决多线程问题(我对多线程很陌生)。 我正在尝试设计一个可以与多个线程共享的RESTFUL Web服务API的Facade类。 我正在使用HttpURLConnection进行连接,而Google GSON则用于转换JSON数据和从JSON数据转换。

以下是我到目前为止的课程。 在这个例子中,它有一个公共方法来进行API调用(authenticateCustomer()),私有方法用于促进API调用(即构建POST数据字符串,发出POST请求等)。

我创建了这个类的一个实例并与1000个线程共享它。 线程调用authenticateCustomer()方法。 大多数线程都可以工作,但有些线程会获得空指针异常,这是因为我没有实现任何同步。 如果我使authenticateCustomer()方法'同步'它的工作原理。 问题是这导致并发性差(例如,POST请求突然需要很长时间才能完成,这将阻止所有其他线程)。

现在问我的问题。 下面的类不是无状态的,因此是线程安全的吗? 类中的极少数字段被声明为final,并在构造函数中赋值。 所有方法都使用局部变量。 Gson对象是无状态的(根据他们的网站)并且无论如何都在API方法中创建为局部变量。

public final class QuizSyncAPIFacade 
{
    // API Connection Details
private final String m_apiDomain;
private final String m_apiContentType;
private final int m_bufferSize;

// Constructors
public QuizSyncAPIFacade()
{
    m_apiDomain      = "http://*****************************";
    m_apiContentType = ".json";
    m_bufferSize = 8192; // 8k
}

private String readInputStream(InputStream stream) throws IOException
{
        // Create a buffer for the input stream
    byte[] buffer = new byte[m_bufferSize];

    int readCount;

    StringBuilder builder = new StringBuilder();

    while ((readCount = stream.read(buffer)) > -1) {
        builder.append(new String(buffer, 0, readCount));
    }

    return builder.toString();
}

private String buildPostData(HashMap<String,String> postData) throws UnsupportedEncodingException
{
    String data = "";

    for (Map.Entry<String,String> entry : postData.entrySet()) 
    {
        data += (URLEncoder.encode(entry.getKey(), "UTF-8") + "=" + URLEncoder.encode(entry.getValue(), "UTF-8") + "&");        
    }

    // Trim the last character (a trailing ampersand)
    int length = data.length();

    if (length > 0) {
        data = data.substring(0, (length - 1));
    }

    return data;
}

private String buildJSONError(String message, String name, String at)
{
    String error = "{\"errors\":[{\"message\":\"" + message + "\",\"name\":\"" + name + "\",\"at\":\"" + at + "\"}]}";

    return error;
}

private String callPost(String url, HashMap<String,String> postData) throws IOException
{
    // Set up the URL for the API call 
    URL apiUrl = new URL(url);

    // Build the post data
    String data = buildPostData(postData);

    // Call the API action
    HttpURLConnection conn;

    try {
        conn = (HttpURLConnection)apiUrl.openConnection();
    } catch (IOException e) {
        throw new IOException(buildJSONError("Failed to open a connection.", "CONNECTION_FAILURE", ""));
    }

    // Set connection parameters for posting data
    conn.setRequestMethod("POST");
    conn.setUseCaches(false);
    conn.setDoInput(true);
    conn.setDoOutput(true);

    // Write post data
    try {
        DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
        wr.writeBytes(data);
        wr.flush();
        wr.close();
    } catch (IOException e) {
        throw new IOException(buildJSONError("Failed to post data in output stream (Connection OK?).", "POST_DATA_FAILURE", ""));           
    }

    // Read the response from the server                
    InputStream is;

    try {
        is = conn.getInputStream();
    } catch (IOException e) {
        InputStream errStr = conn.getErrorStream();

        if (errStr != null) 
        {
            String errResponse = readInputStream(errStr);
            throw new IOException(errResponse);
        } 
        else 
        {
            throw new IOException(buildJSONError("Failed to read error stream (Connection OK?).", "ERROR_STREAM_FAILURE", ""));
        }
    }

    // Read and return response from the server
    return readInputStream(is);
}

/* -------------------------------------
 * 
 * Synchronous API calls
 * 
   ------------------------------------- */

public APIResponse<CustomerAuthentication> authenticateCustomer(HashMap<String,String> postData)
{
    // Set the URL for this API call
    String apiURL = m_apiDomain + "/customer/authenticate" + m_apiContentType;

    Gson jsonConv = new Gson();

    String apiResponse = "";

    try 
    { 
        // Call the API action
        apiResponse = callPost(apiURL, postData);

        // Convert JSON response to the required object type
        CustomerAuthentication customerAuth = jsonConv.fromJson(apiResponse, CustomerAuthentication.class);

        // Build and return the API response object
        APIResponse<CustomerAuthentication> result = new APIResponse<CustomerAuthentication>(true, customerAuth, null);

        return result;
    } 
    catch (IOException e) 
    {
        // Build and return the API response object for a failure with error list
        APIErrorList errorList = jsonConv.fromJson(e.getMessage(), APIErrorList.class);

        APIResponse<CustomerAuthentication> result = new APIResponse<CustomerAuthentication>(false, null, errorList);

        return result;
    }
}

}


Apologies for the long code post but am wondering if someone can help with a multithreading question (I am quite new to multi-threading). I am trying to design a facade class to a RESTFUL web services API that can be shared with multiple threads. I am using HttpURLConnection to do the connection and Google GSON to convert to and from JSON data.

The below class is what I have so far. In this example it has one public method to make an API call (authenticateCustomer()) and the private methods are used to facilitate the API call (i.e to build the POST data string, make a POST request etc).

I make one instance of this class and share it with 1000 threads. The threads call the authenticateCustomer() method. Most of the threads work but there is some threads that get a null pointer exception which is because I haven't implemented any synchronization. If I make the authenticateCustomer() method 'synchronized' it works. The problem is this results in poor concurrency (say, for example, the POST request suddenly takes a long time to complete, this will then hold up all the other threads).

Now to my question. Is the below class not stateless and therefore thread-safe? The very few fields that are in the class are declared final and assigned in the constructor. All of the methods use local variables. The Gson object is stateless (according to their web site) and created as a local variable in the API method anyway.

public final class QuizSyncAPIFacade 
{
    // API Connection Details
private final String m_apiDomain;
private final String m_apiContentType;
private final int m_bufferSize;

// Constructors
public QuizSyncAPIFacade()
{
    m_apiDomain      = "http://*****************************";
    m_apiContentType = ".json";
    m_bufferSize = 8192; // 8k
}

private String readInputStream(InputStream stream) throws IOException
{
        // Create a buffer for the input stream
    byte[] buffer = new byte[m_bufferSize];

    int readCount;

    StringBuilder builder = new StringBuilder();

    while ((readCount = stream.read(buffer)) > -1) {
        builder.append(new String(buffer, 0, readCount));
    }

    return builder.toString();
}

private String buildPostData(HashMap<String,String> postData) throws UnsupportedEncodingException
{
    String data = "";

    for (Map.Entry<String,String> entry : postData.entrySet()) 
    {
        data += (URLEncoder.encode(entry.getKey(), "UTF-8") + "=" + URLEncoder.encode(entry.getValue(), "UTF-8") + "&");        
    }

    // Trim the last character (a trailing ampersand)
    int length = data.length();

    if (length > 0) {
        data = data.substring(0, (length - 1));
    }

    return data;
}

private String buildJSONError(String message, String name, String at)
{
    String error = "{\"errors\":[{\"message\":\"" + message + "\",\"name\":\"" + name + "\",\"at\":\"" + at + "\"}]}";

    return error;
}

private String callPost(String url, HashMap<String,String> postData) throws IOException
{
    // Set up the URL for the API call 
    URL apiUrl = new URL(url);

    // Build the post data
    String data = buildPostData(postData);

    // Call the API action
    HttpURLConnection conn;

    try {
        conn = (HttpURLConnection)apiUrl.openConnection();
    } catch (IOException e) {
        throw new IOException(buildJSONError("Failed to open a connection.", "CONNECTION_FAILURE", ""));
    }

    // Set connection parameters for posting data
    conn.setRequestMethod("POST");
    conn.setUseCaches(false);
    conn.setDoInput(true);
    conn.setDoOutput(true);

    // Write post data
    try {
        DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
        wr.writeBytes(data);
        wr.flush();
        wr.close();
    } catch (IOException e) {
        throw new IOException(buildJSONError("Failed to post data in output stream (Connection OK?).", "POST_DATA_FAILURE", ""));           
    }

    // Read the response from the server                
    InputStream is;

    try {
        is = conn.getInputStream();
    } catch (IOException e) {
        InputStream errStr = conn.getErrorStream();

        if (errStr != null) 
        {
            String errResponse = readInputStream(errStr);
            throw new IOException(errResponse);
        } 
        else 
        {
            throw new IOException(buildJSONError("Failed to read error stream (Connection OK?).", "ERROR_STREAM_FAILURE", ""));
        }
    }

    // Read and return response from the server
    return readInputStream(is);
}

/* -------------------------------------
 * 
 * Synchronous API calls
 * 
   ------------------------------------- */

public APIResponse<CustomerAuthentication> authenticateCustomer(HashMap<String,String> postData)
{
    // Set the URL for this API call
    String apiURL = m_apiDomain + "/customer/authenticate" + m_apiContentType;

    Gson jsonConv = new Gson();

    String apiResponse = "";

    try 
    { 
        // Call the API action
        apiResponse = callPost(apiURL, postData);

        // Convert JSON response to the required object type
        CustomerAuthentication customerAuth = jsonConv.fromJson(apiResponse, CustomerAuthentication.class);

        // Build and return the API response object
        APIResponse<CustomerAuthentication> result = new APIResponse<CustomerAuthentication>(true, customerAuth, null);

        return result;
    } 
    catch (IOException e) 
    {
        // Build and return the API response object for a failure with error list
        APIErrorList errorList = jsonConv.fromJson(e.getMessage(), APIErrorList.class);

        APIResponse<CustomerAuthentication> result = new APIResponse<CustomerAuthentication>(false, null, errorList);

        return result;
    }
}

}


原文:https://stackoverflow.com/questions/10447969
更新时间:2024-02-28 16:02

最满意答案

即使我没有按照json-api传递数据,仍然必须设置pointer ,好像我是:

{
    "errors": [{
        "code": null,
        "detail": "may not be null",
        "status": null,
        "title": null,
        "source": {
            "pointer": "/data/attributes/name",
            "parameter": null
        }
    }]
}

even though I'm not passing in the data per the json-api, the pointer still had to be set as if I were:

{
    "errors": [{
        "code": null,
        "detail": "may not be null",
        "status": null,
        "title": null,
        "source": {
            "pointer": "/data/attributes/name",
            "parameter": null
        }
    }]
}

相关问答

更多
  • 我不是100%肯定你从哪里获得了serializer属性,但我不确定它确实存在。 适配器上有一个defaultSerializer属性可以工作,但是它带有一些奇怪的优先级规则。 如果我是你,我会通过将它放在serializers/account.js中以Ember CLI方式声明序列化程序,并从适配器中删除serializer属性。 I'm not 100% sure where you got the serializer property from, but I'm not sure that actu ...
  • 部分响应:通过查看此处的HTTP消息生命周期,可以在HttpRoutingDispatcher之前的管道中尽早添加消息处理程序。 所以,创建一个处理程序类: public class NotAllowedMessageHandler : DelegatingHandler { protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancel ...
  • 您是否尝试将故事声明为嵌入在频道序列化程序中? export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { stories: { embedded: 'always' } }, normalizeArrayResponse(store, primaryModelClass, hash, id, requestType) { ... }); Did you try to declare s ...
  • 即使我没有按照json-api传递数据,仍然必须设置pointer ,好像我是: { "errors": [{ "code": null, "detail": "may not be null", "status": null, "title": null, "source": { "pointer": "/data/attributes/name", "parameter ...
  • C ++标准库的头文件( iostream , vector等)最后没有.h 。 (然而,大多数第三方库确实使用.h 。由于std_lib_facilities.h确实有.h,所以假设它不是一个标准库并不是Visual C ++应该提供的东西是合理的。 在这种情况下,快速的谷歌搜索显示它随书提供,可从http://www.stroustrup.com/Programming/std_lib_facilities.h下载。 The C++ Standard Library's header files (io ...
  • 为什么不总是给它们ExampleAppDomain作为错误的域。 在这方面,没有混乱。 大多数标准库都这样做 - 封装所有错误。 基本上,当您收到错误时,您需要将您的域包装在NSError中。 您可以检查响应的NSURLConnectionDelegate的可接受statusCode和内容。 此外,为什么不使用像AFNetworking这样的标准库,而不是自己处理所有网络代码? 这是一个代码,但您必须检查基于XML / JSON的可接受的代码/内容。 以下是AFNetworking的摘录。 NSMutabl ...
  • 你在用JSF2吗? 如果是,则可以在web.xml中注册ExceptionHandlerFactory,而不是编写Interceptor, 如此处所述 。 在CustomExceptionHandler中,您可以捕获所有异常并以编程方式处理它们。 我在我的JEE6-CDI-app中使用这种方法,发现它很好。 Are you using JSF2? If yes, instead of writing an Interceptor, you could register an ExceptionHandler ...
  • 您有3个主要选择: 基于字符串,即查看消息。 这当然非常糟糕,因为如果你以后更改了邮件中的一个字母,你需要重写所有的检查代码,所以我会避免它。 如果错误消息可以保持不变,只需将错误创建为全局变量,然后将接收到的错误与已知的预定错误进行比较。 例如: var ErrDB = errors.New("Database Error") var ErrTimeout = errors.New("Timeout") //or whatever 接着 if err := someFunc(); err != nil ...
  • 您需要使用常规的异常处理方法来处理它们 export class TaskService { private _url = "api/products/datanew.json"; constructor(private _http: Http) { } getTasks(): Observable { return this._http.get(this._url) .map((response: Response) = ...
  • 从find方法返回json时,您需要获得所有可用于同步使用的信息。 很容易正确地扩展find方法(并且不必担心将来会破坏它)。 App.ApplicationAdapter = DS.RESTAdapter.extend({ find: function(store, type, id) { var self; return this._super(store, type, id).then(function(json){ return self.someAsyncMetho ...

相关文章

更多

最新问答

更多
  • 获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)
  • 如何通过引用返回对象?(How is returning an object by reference possible?)
  • 矩阵如何存储在内存中?(How are matrices stored in memory?)
  • 每个请求的Java新会话?(Java New Session For Each Request?)
  • css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)
  • 无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)
  • xcode语法颜色编码解释?(xcode syntax color coding explained?)
  • 在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)
  • 从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)
  • 从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))
  • 西安哪有PLC可控制编程的培训
  • 在Entity Framework中选择基类(Select base class in Entity Framework)
  • 在Android中出现错误“数据集和渲染器应该不为null,并且应该具有相同数量的系列”(Error “Dataset and renderer should be not null and should have the same number of series” in Android)
  • 电脑二级VF有什么用
  • Datamapper Ruby如何添加Hook方法(Datamapper Ruby How to add Hook Method)
  • 金华英语角.
  • 手机软件如何制作
  • 用于Android webview中图像保存的上下文菜单(Context Menu for Image Saving in an Android webview)
  • 注意:未定义的偏移量:PHP(Notice: Undefined offset: PHP)
  • 如何读R中的大数据集[复制](How to read large dataset in R [duplicate])
  • Unity 5 Heighmap与地形宽度/地形长度的分辨率关系?(Unity 5 Heighmap Resolution relationship to terrain width / terrain length?)
  • 如何通知PipedOutputStream线程写入最后一个字节的PipedInputStream线程?(How to notify PipedInputStream thread that PipedOutputStream thread has written last byte?)
  • python的访问器方法有哪些
  • DeviceNetworkInformation:哪个是哪个?(DeviceNetworkInformation: Which is which?)
  • 在Ruby中对组合进行排序(Sorting a combination in Ruby)
  • 网站开发的流程?
  • 使用Zend Framework 2中的JOIN sql检索数据(Retrieve data using JOIN sql in Zend Framework 2)
  • 条带格式类型格式模式编号无法正常工作(Stripes format type format pattern number not working properly)
  • 透明度错误IE11(Transparency bug IE11)
  • linux的基本操作命令。。。