# An Automated Refactoring Approach to Improve IoT Software Quality
## 4 Refactoring for Fine-Grained ReentrantReadWriteLocks
### Lock Mode  
Our refactoring tool transforms a built-in monitor into a fine-grained _ReentrantReadWriteLock_ by lock downgrading and lock splitting.  
Figure 3: The refactoring framework.  
Our refactoring tool directly applies the read locks to methods and synchronization blocks that have no side effects. For methods or blocks with side effects, the write locks, downgrading locks and splitting locks are used.  
The fine-grained lock mode shown in Figure 4 is implemented by lock downgrading [29]. Figure 4a shows the program before refactoring. The method _cache()_ will first judge the conditional variant _flag_. Only when the _flag_ is true, the write operations will be executed.  
Figure 4b presents the program after refactoring. Under the control of a read lock, a conditional statement _flag_ is read (Line 4). If the condition is met, write operations are executed. Therefore, the current thread will release the read lock (Line 5) and acquire the write lock (Line 6) to perform the write operations. Note that a thread needs to release the read lock before getting the write lock. After acquiring the write lock, the conditional state will be rechecked (Line 7) in case other threads acquire the write lock and modify the state.  
Figure 5 shows three fine-grained locking modes through splitting of the _RentrantReadWriteLock_. Figure 5a shows the code before refactoring, and Figure 5b presents the code after refactoring. In the code of Figure 5b, the read lock is used to read the conditional statement (Line 5). If the conditional state is true, the read lock is released (Line 6), and then the write lock is acquired. The _finally_ block will check what lock the thread is holding (Line 13). The write lock will be released when the write lock is held by the thread, and the read lock will be released when the read lock is held.  
Other refactoring implementations shown in Figure 5c may cause threads to lose their perception of data updates. For instance, the section protected by the write lock has a write operation on the shared variable \(s\), and the section protected by the read lock has a read operation on \(s\). This will cause a problem: the thread may not read the data it has already modified. Synchronization problems may arise when the section protected by the write lock and the section protected by the read lock have the same shared variables.  
We made a precondition that the read and write operations cannot access the same variable for refactoring under this mode. Because two operations access the same variable, the visibility of the data will be lost. For example, thread A acquires the read lock and reads the value of variable \(i\), then releases the read lock. Thread B acquires write lock and modifies the value of variable \(i\). But thread A cannot know the update of the value.  
Figure 4: (a) Method _cache()_ based on built-in monitors. (b) Method _cache()_ using the lock downgrading of _RentrantReadWriteLacks_  
We put the shared variables read by the read lock into the list _readlist_, and the shared variables written by the write lock into the collection _writelist_. If the two lists do not share the same element, the refactoring tool uses the read lock. Otherwise, the tool uses the write lock for refactoring.