We saw two non access modifiers in the last article. We examine final and synchronized in this article. We will examine abstract, transient, native and volatile modifiers in the next lesson.
The final Modifier
final is one of the most frequently non access modifiers. final may qualify –
- Variables (including local, instance and method arguments)
- Classes
- Methods
final Variables
- A final variable acts as constant
- A final variable can be initialized exactly once
- The unique selling proposition of final variable is that it can never be changed. Once you initialize and release (possibly by making public or protected) the variable, others can read it but not change it.
- A final variable of primitive type implies that the value contained in the variable can never change. It is possible to create non-final copy of a final variable.
- A final reference type variable implies that the variable will continue to point the object it was pointing to after initialization. The object being referenced may undergo change (through a final reference or through other references). It is possible to create a non-final copy of final reference variable.
final Classes
- A class is nothing but bunch of instructions and a template for data.
- A final class therefore implies that the instructions (statements) contained in the class can not be modified in anyway.
- The observation #2 means that a final class cannot be extended. Because extending the class will add (and may be modify) instructions.
final Methods
- A method is nothing but bunch of instructions.
- A final method therefore implies that the instructions (statements) contained in the method can not be modified in anyway.
- The observation #2 means that a final method cannot be overriden in a sub class. The instructions are fixed as soon as you declare them final.
The synchronized Modifier
The main objective of synchronized modifier is to prevent thread interference. If an object is visible to more than one thread, different threads may access the object same time and cause memory problems. The synchronized modifier ensures that even when multiple threads can see an object, only one of them is able to executed code (through methods and code blocks) on that object.
Therefore, synchronized modifier can be applied to
- Methods
- Code Blocks
A synchronized modifier ensures that one and exactly one thread is executing the code within synchronized method or block.
Synchronization is a fairly important topic and will be discussed in great details in Java concurrency lessons. Those lessons also cover the case when synchronized is mixed with static.
synchronized Methods
- synchronized methods of an object allow one thread to execute at a time.
- If there are multiple threads wanting to execute a synchronized method of an object, one of the thread is chosen to execute the method. The other threads block and wait.
- When a thread completes the execution of a synchronized method, threads waiting for the execution of synchronized method are activated and again one thread is selected is random. This process continues as long as there are threads blocked on a synchronized method.
- State changes are persistent. Whatever changes to the state occur as a result of a method invocation by a thread are all visible to the next thread as well as all other threads.
synchronized Code Blocks
A synchronized code block is a piece of code contained within ‘synchronized {‘ and ‘}.
Whatever was said about synchronized methods applies verbatim to synchronized block. A synchronization block gives you the flexibility of increasing or decreasing the granularity of synchronization. Consider these examples –
- You have a method where only a few lines access shared resource. You can decrease the granularity of your synchronized method by making only those few lines synchronized in a block. This reduced the amount of time threads would be blocked.
1234567891011121314151617181920212223// assume this to be part of our // Politician class public void robPeople() { // no shared resources involved in lecturing // people. just continue ranting lecturePeople(); synchronized { // accessing public money and transferring // it to your account needs to be // synchronized. // There will be other objects // (may be other Politicians) // who will have access to public money. // So,the politician accesses the money in a synchronized // block when no one else can do the same thing. takePublicMoney(); } // end of synchronized block …
- You have two or more methods which are a part of the same logical operation. Making each method synchronized separately does not help. Thread interference and memory corruption can occur in the interval between (or during) execution of method. So, you can club all such methods together in a synchronized block. Continuing with our example of the robbing politician, he has to also clean his tracks after robbing people’s money. He would be in some (politicians are never in big) trouble if cops come knocking at his door between the time he takes public money and cleans his tracks. The politician must ensure that he is able to clean his tracks before some else checks public accounts.
1234567891011121314151617181920212223 | // assume this to be part of our // Politician class public void robPeople() { // no shared resources involved in lecturing // people. just continue ranting lecturePeople(); synchronized { // accessing public money, cleaning your tracks // needs to be synchronized. // The politician must ensure that no one // else accesses public money account // before he has cleaned his tracks. takePublicMoney(); cleanMyTracks(); } // end of synchronized block … |
In the upcoming lesson, we will examine the remaining non access modifiers volatile, transient and abstract.