多线程(无状态类)(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
最满意答案
即使我没有按照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 ...
-
处理405个错误(Handling 405 errors)[2023-12-10]
部分响应:通过查看此处的HTTP消息生命周期,可以在HttpRoutingDispatcher之前的管道中尽早添加消息处理程序。 所以,创建一个处理程序类: public class NotAllowedMessageHandler : DelegatingHandler { protected override async TaskSendAsync(HttpRequestMessage request, CancellationToken cancel ... -
EmberJS RESTSerializer与嵌入的hasMay关系(EmberJS RESTSerializer with embedded hasMay relationship)[2022-06-01]
您是否尝试将故事声明为嵌入在频道序列化程序中? 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 ...
-
用iostream处理错误(Handling errors with iostream)[2023-04-01]
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 ...
-
CDI - 处理错误(CDI - handling errors)[2023-10-29]
你在用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 ... -
处理多个错误(Handling multiple errors)[2022-04-27]
您有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 ...