Why use Sync?
Java allows multithreading concurrency control, when multiple threads concurrently manipulate a shareable resource variable (such as data additions and deletions),
will result in inaccurate data and conflict with each other, so join a sync lock to avoid being called by another thread until the thread has completed the operation.
Thus, the uniqueness and accuracy of the variable are ensured.
1. Synchronization method
That is, there are methods for synchronized keyword modification.
Because every object in Java has a built-in lock, when the method is modified with this keyword,
Built-in locks protect the entire method. You need to get the built-in lock before calling the method, otherwise it will be in a blocking state.
Code such as:
Public synchronized void Save () {}
Note: The Synchronized keyword can also modify a static method, at which point the entire class is locked if the static method is called.
2. Synchronizing code blocks
That is, a statement block that has the synchronized keyword modifier.
Statement blocks that are decorated with this keyword are automatically added with built-in locks for synchronization
Code such as:
Synchronized (object) { }
Note: Synchronization is a high-overhead operation, so you should minimize the content of synchronization.
It is usually not necessary to synchronize the entire method, using the synchronized code block to synchronize the key code.
code example:
Package com.xhj.thread; /** * Application of thread synchronization * * @author Xiehejun * * */public class Synchronizedthread {class Bank { private int account = 100; public int Getaccount () {return account; }/** * * * * @param money */Public Synchron with synchronous method ized void Save (int money) {account + = money; }/** * Implemented with synchronous code blocks * * @param money */public void SA ve1 (int money) {synchronized (the) {account + = money; }}} class Newthread implements Runnable {private Bank bank; Public Newthread (Bank bank) {this.bank = Bank; } @Override public void Run () {for (int i = 0; i < i++) { Bank.sAVE1 (10); Bank.save (10); SYSTEM.OUT.PRINTLN (i + "account balance:" + bank.getaccount ()); }}}/** * Build thread, call inner class */public void Usethread () {Bank = New Bank (); Newthread new_thread = new Newthread (bank); SYSTEM.OUT.PRINTLN ("Thread 1"); Thread thread1 = new Thread (new_thread); Thread1.start (); SYSTEM.OUT.PRINTLN ("Thread 2"); Thread thread2 = new Thread (new_thread); Thread2.start (); } public static void Main (string[] args) {Synchronizedthread st = new Synchronizedthread (); St.usethread (); } }
3. Using special domain variables (volatile) for thread synchronization
The A.volatile keyword provides a lock-free mechanism for accessing domain variables.
B. Using a volatile modifier domain is equivalent to telling a virtual machine that the domain might be updated by another thread.
C. Therefore, each time the domain is used, it is recalculated instead of using the value in the Register
D.volatile does not provide any atomic manipulation, nor can it be used to modify a final type of variable
For example:
In the example above, thread synchronization can be achieved simply by adding a volatile modifier to the account.
code example:
Just give the code to be modified, the rest of the code with the same class Bank { //the variable that needs to be synchronized plus the volatile private volatile int account = +; public int Getaccount () { return account; } There is no longer a need for synchronized public void Save (int money) {Account + = money; } }
Note: The non-synchronous problem in multi-threading is mainly in the reading and writing of the domain, and if the domain itself avoids this problem, it is not necessary to modify the method of manipulating the domain.
With the final domain, locked-protected and volatile domains can avoid unsynchronized problems.
4. Using a re-entry lock for thread synchronization
A java.util.concurrent package has been added to support synchronization in JavaSE5.0.
The Reentrantlock class is a lock that can be re-entrant, mutually exclusive, and implements the lock interface.
It has the same basic behavior and semantics as using the Synchronized method and fast, and expands its capabilities
Common methods of the Reenreantlock class are:
Reentrantlock (): Create an Reentrantlock instance
Lock (): Get lock
Unlock (): Release lock
Note: Reentrantlock () also has a construction method that can create a fair lock, but is not recommended because it can significantly reduce the efficiency of program operation
For example:
On the basis of the above example, the rewritten code is:
code example:
Just give the code to be modified, the rest of the code with the same class Bank { private int account = +; Need to declare this lock private lock lock = new Reentrantlock (); public int Getaccount () { return account; } Synchronized public void Save (int money) { lock.lock () is no longer required here; try{account + = money; } finally{ Lock.unlock (); } } }
Note: About the lock object and synchronized keyword selection:
A. It is best to use one of the mechanisms provided by the java.util.concurrent package, preferably two.
Ability to help users with all lock-related code.
B. If the synchronized keyword satisfies the user's needs, use synchronized because it simplifies the code
C. If you need more advanced features, use the Reentrantlock class, you should pay attention to release the lock in time, otherwise there will be deadlock, usually in the finally code release lock
5. Using local variables for thread synchronization
If you use threadlocal to manage variables, each thread that uses the variable obtains a copy of the variable.
Replicas are independent of each other so that each thread is free to modify its own copy of the variable without affecting other threads.
Common methods of ThreadLocal class
ThreadLocal (): Create a thread-local variable
Get (): Returns the value in the current thread copy of this thread's local variable
InitialValue (): Returns the "initial value" of the current thread for this thread's local variables
Set (T value): Sets the value in the current thread copy of this thread's local variable to value
For example:
On the basis of the above example, the modified code is:
code example:
Change the Bank class only, the rest of the code with the public class bank{ //Use ThreadLocal class to manage shared variables account private static threadlocal< integer> account = new threadlocal<integer> () { @Override protected Integer initialvalue () { return;} ; public void Save (int money) { account.set (Account.get () +money); } public int Getaccount () { return account.get (); } }
Note: threadlocal and synchronization mechanism
The a.threadlocal and synchronization mechanisms are all designed to solve the problem of access violation of the same variable in multi-threading.
B. The former adopts a "space-for-time" approach, which uses a "time-for-space" approach
6. Using blocking queues for thread synchronization
The previous 5 synchronization methods are synchronous at the bottom of the thread, but we should try to stay away from the underlying structure as far as possible in actual development.
Using the new Java.util.concurrent package in the javaSE5.0 release will help simplify development.
This section mainly uses linkedblockingqueue<e> to implement thread synchronization.
Linkedblockingqueue<e> is a blocking queue that is based on a connected node, in any range.
Queues are first in, out order (FIFO), and the queue will be explained in detail ~
Common methods of Linkedblockingqueue class
Linkedblockingqueue (): Create a linkedblockingqueue with a capacity of integer.max_value
Put (E): Add an element at the end of the queue and block if it is full
Size (): Returns the number of elements in the queue
Take (): Removes and returns the team header element, which is blocked if the queue is empty
code Example:
To achieve the synchronization of business products and trading goods
1 package com.xhj.thread; 2 3 Import Java.util.Random; 4 Import Java.util.concurrent.LinkedBlockingQueue; 5 6/** 7 * Use a blocking queue for thread synchronization linkedblockingqueue 8 * 9 * @author XIEHEJUN10 * */12 public class Blockingsynchroniz Edthread {13/**14 * defines a blocking queue for storing manufactured goods */16 private linkedblockingqueue<integer> queue = new L Inkedblockingqueue<integer> (); 17/**18 * Defines the number of goods produced */20 private static final int size = 10;21 /**22 * Defines the boot thread flag, which is 0 o'clock to start the thread of the production commodity; for 1 o'clock, the thread that started the consumer product is */24 private int flag = 0;25 to the private class Linkblock Thread implements Runnable {@Override28 public void run () {New_flag int = flag++;30 SYSTEM.OUT.PRINTLN ("Boot thread" + new_flag), and if (New_flag = = 0) {(int i = 0; i < size; i++) {$ int b = new Random (). Nextint (255); System.out.println ("Product:" + B + "No." ), and try {Queue.put (b); PNs} catch (Interruptedexception e) {38 TODO auto-generated catch block39 e.printstacktrace (); 40}41 SYSTEM.OUT.PRINTLN ("There are goods in the warehouse:" + queue.size () + "X"); Sleep (interruptedexception e) {gb//TODO auto-generated CATC H block46 e.printstacktrace ();}48}49} else {5 0 for (int i = 0; i < SIZE/2; i++) {n = try {qu int Eue.take (); System.out.println ("The consumer buys the" + N + "product"); Exception e) {//TODO auto-generated catch block56 e.printstacktrace (); 57}SYSTEM.OUT.PRINTLN ("There are goods in the warehouse:" + queue.size () + "X"); Thread.Sleep (+); catch (Exception e) {//Todo:handle Excepti on63}64}65}66}67}68 public static void main (String [] args) {blockingsynchronizedthread BST = new Blockingsynchronizedthread (); Linkblockthread LBT = BS T.new Linkblockthread (); thread1 thread = new Thread (LBT); thread2 = new Thread (LBT); 74 Thread1.start (); Thread2.start (); 76 77}78 79}
Note:blockingqueue<e> defines the common methods of blocking queues, especially three ways to add elements, and we should pay more attention when the queue is full:
The Add () method throws an exception
Offer () method returns false
The put () method blocks
7. Using atomic variables for thread synchronization
The root cause of the need to use thread synchronization is that operations on ordinary variables are not atomic.
So what is atomic manipulation?
Atomic manipulation means reading the value of a variable, modifying the value of a variable, saving a variable value as a whole.
That is, these kinds of behaviors are either completed at the same time or not completed.
A tool class that creates an atomic type variable is provided in the Java util.concurrent.atomic package.
Use this class to simplify thread synchronization.
Where the atomicinteger table can atomically update the value of int, available in the application (such as an atomic increment of the counter),
But it cannot be used to replace integers; Extensible number allows for uniform access to tools and utilities that handle the opportunity numbers class.
Common methods of the Atomicinteger class:
Atomicinteger (int initialvalue): Creates a new atomicinteger with the given initial value
Addaddget (int dalta): atomically adds the given value to the current value
Get (): Gets the current value
code example:
Just change the bank class, the rest of the code is the same as the first example above
1 class Bank {2 private Atomicinteger account = new Atomicinteger, 3 4 public Atomicinteger Getaccount () {5 return account, 6 } 7 8 public void Save (int money) {9 account.addandget (money); }11 }
Complementary-atomic operations are mainly:
Read and write operations for reference variables and most primitive variables (except long and double);
Read and write operations for all variables that use volatile modifiers, including long and double.
Related articles:
A detailed explanation of Java thread synchronization and synchronization methods
A detailed approach to thread synchronization in Java multithreaded programming