...
Wiki Markup |
---|
If the Java Virtual Machine (JVM) interacts with a file system that operates over an unreliable network, file I/O might incur a large performance penalty. In such cases, avoid file I/O over the network when holding a lock. File operations (such as logging) that may block waiting for the output stream lock or for I/O to complete may be performed in a dedicated thread to speed up task processing. Logging requests can be added to a queue given that the queue's {{put()}} operation incurs little overhead as compared to file I/O \[[Goetz 06, pg 244|AA. Java References#Goetz 06]\]. |
Noncompliant Code Example (
...
Deferring a
...
Thread)
This noncompliant code example defines a utility method that accepts a time
parameter argument.
Code Block | ||
---|---|---|
| ||
public synchronized void doSomething(long time) throws InterruptedException { // ... Thread.sleep(time); } |
...
This compliant solution defines the doSomething()
method with a timeout
parameter instead of the time
value. The use of the Using Object.wait()
method instead of Thread.sleep()
allows setting a time out for a period during which a notification may awaken the thread.
...
The current object's monitor is immediately released upon entering the wait state. After the time out period has elapsed, the thread attempts to reacquire resumes execution after reacquiring the current object's monitor and resumes execution when it succeeds.
Wiki Markup |
---|
According to the Java API class {{Object}} documentation \[[API 06|AA. Java References#API 06]\]: |
...
Ensure that a thread that holds locks on other objects releases them appropriately, before entering the wait state. Also, refer to the related guidelines Additional guidance on waiting and notification in available in CON18-J. Always invoke wait() and await() methods inside a loop and CON19-J. Notify all waiting threads instead of a single thread.
...
Code Block | ||
---|---|---|
| ||
// Class Page is defined separately. It stores and returns the Page name via getName() Page[] pageBuff = new Page[MAX_PAGE_SIZE]; public synchronized boolean sendPage(Socket socket, String pageName) throws IOException { // Get the output stream to write the Page to ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); // Find the Page requested by the client (this operation requires synchronization) Page targetPage = null; for (Page p : pageBuff) { if (p.getName().compareTo(pageName) == 0) { targetPage = p; } } // Requested Page does not exist if (targetPage == null) { return false; } // Send the Page to the client (does not require any synchronization) out.writeObject(targetPage); out.flush(); out.close(); return true; } |
...
Compliant Solution
This compliant solution entails separating separates the actions process into a sequence of steps:
- Perform actions on data structures requiring synchronization
- Create copies of the objects that are required to be sent
- Perform network calls in a separate method that does not require any synchronization
In this compliant solution, the synchronized method getPage()
is called from an unsynchronized method sendPage()
, to find retrieve the requested Page
in the pageBuff
array. After the Page
is retrieved, the method sendPage()
calls the unsynchronized method deliverPage()
to deliver the Page
to the client.
Code Block | ||
---|---|---|
| ||
public boolean sendPage(Socket socket, String pageName) { // No synchronization Page targetPage = getPage(pageName); if (targetPage == null) return false; return deliverPage(socket, targetPage); } private synchronized Page getPage(String pageName) { // Requires synchronization Page targetPage = null; for (Page p : pageBuff) { if (p.getName().equals(pageName)) { targetPage = p; } } return targetPage; } public boolean deliverPage(Socket socket, Page page){ try{ // Get the output stream to write the Page to ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); // Send the Page to the client out.writeObject(page); } catch (IOException io){ // If recovery is not possible return false return false; } finally { out.flush(); out.close(); } return true; } |
Exceptions
EX1: Classes that are compliant with the guideline provide an appropriate termination mechanism to callers are allowed to violate this guideline (see CON24-J. Ensure that threads and tasks performing blocking operations can be terminated in that they provide an appropriate termination mechanism to callers, are allowed to violate this guideline).
EX2: A method that requires multiple locks may hold several locks while waiting for the remaining locks to become available. This constitutes a valid exception, though care must be taken to avoid deadlock. See CON12-J. Avoid deadlock by requesting and releasing locks in the same order for more information.
Risk Assessment
If blocking Blocking or time consuming lengthy operations are performed within synchronized regions , temporary or permanent deadlock may result in a deadlocked or unresponsive system.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
CON20-J | low | probable | high | P2 | L3 |
...