Several ways to achieve thread synchronization

Several ways to achieve thread synchronization

Reprinted: https://blog.csdn.net/Small_Lee/article/details/51453019

 

Why use sync?

Java allows multi-threaded concurrency control. When multiple threads operate a shared resource variable at the same time (such as adding, deleting, modifying and checking data), the 
data will be inaccurate and conflict with each other. Therefore, a synchronization lock is added to avoid this problem. Before the thread completes the operation, it is called by other threads, 
thus ensuring the uniqueness and accuracy of the variable.

way of synchronization

1. Synchronized methods 
are methods modified by the synchronized keyword. 
Since each object of java has a built-in lock, when a method is decorated with this keyword, the 
built-in lock protects the entire method. Before calling this method, you need to acquire the built-in lock, otherwise it will be blocked.

代码如: 
public synchronized void save(){}
  • 1
  • 2
  • 3

Note: The synchronized keyword can also modify static methods. If the static method is called at this time, the entire class will be locked.

2. A synchronized code block 
is a statement block modified by the synchronized keyword. 
The statement block modified by this keyword will be automatically added with a built-in lock to achieve synchronization

代码如: 
synchronized(object){ 
}


注:同步是一种高开销的操作,因此应该尽量减少同步的内容。 
通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。 
package com.xhj.thread;

    /**
     * 线程同步的运用
     * 
     * @author XIEHEJUN
     * 
     */
    public class SynchronizedThread { class Bank { private int account = 100; public int getAccount() { return account; } /** * 用同步方法实现 * * @param money */ public synchronized void save(int money) { account += money; } /** * 用同步代码块实现 * * @param money */ public void save1(int money) { synchronized (this) { 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 < 10; i++) { // bank.save1(10); bank.save(10); System.out.println(i + "账户余额为:" + bank.getAccount()); } } } /** * 建立线程,调用内部类 */ public void useThread() { Bank bank = new Bank(); NewThread new_thread = new NewThread(bank); System.out.println("线程1"); Thread thread1 = new Thread(new_thread); thread1.start(); System.out.println("线程2"); Thread thread2 = new Thread(new_thread); thread2.start(); } public static void main(String[] args) { SynchronizedThread st = new SynchronizedThread(); st.useThread(); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

3. Use special domain variables (volatile) to achieve thread synchronization  a. The
volatile keyword provides a lock-free mechanism for domain variable access, 
b. Using volatile to modify the domain is equivalent to telling the virtual machine that the domain may be updated by other threads, 
c. So every time the field is used, it needs to be recalculated, instead of using the value in the register.  d.
volatile does not provide any atomic operations, and it cannot be used to modify variables of final type

For example: 
In the above example, thread synchronization can be achieved simply by adding volatile modifier in front of account.

代码实例: 
  • 1
  • 2
  class Bank {
            //需要同步的变量加上volatile
            private volatile int account = 100; public int getAccount() { return account; } //这里不再需要synchronized public void save(int money) { account += money; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

The asynchronous problem in multithreading mainly occurs in reading and writing to the domain. If the domain itself avoids this problem, there is no need to modify the method of operating the domain.

4. Thread synchronization using reentrant locks 
A java.util.concurrent package has been added in Java SE 5.0 to support synchronization. 
The ReentrantLock class is a reentrant, mutually exclusive lock that implements the Lock interface. 
It has the same basic behavior and semantics as using the synchronized method and fast, and extends its capabilities.

ReenreantLock类的常用方法有:

    ReentrantLock() : 创建一个ReentrantLock实例 
    lock() : 获得锁 
    unlock() : 释放锁 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
    class Bank {

            private int account = 100;
            //需要声明这个锁
            private Lock lock = new ReentrantLock(); public int getAccount() { return account; } //这里不再需要synchronized public void save(int money) { lock.lock(); try{ account += money; }finally{ lock.unlock(); } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
注:关于Lock对象和synchronized关键字的选择: 
    a.最好两个都不用,使用一种java.util.concurrent包提供的机制, 
        能够帮助用户处理所有与锁相关的代码。 
    b.如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码 
    c.如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5. Use local variables to achieve thread synchronization 
If you use ThreadLocal to manage variables, each thread that uses the variable gets a copy of the variable, and the 
copies are independent of each other, so that each thread can modify its own copy of the variable at will, without will affect other threads.

ThreadLocal 类的常用方法



ThreadLocal() : 创建一个线程本地变量 
get() : 返回此线程局部变量的当前线程副本中的值 
initialValue() : 返回此线程局部变量的当前线程的"初始值" 
set(T value) : 将此线程局部变量的当前线程副本中的值设置为value



例如: 
    在上面例子基础上,修改后的代码为: 

代码实例:
    public class Bank{
            //使用ThreadLocal类管理共享变量account
            private static ThreadLocal<Integer> account = new ThreadLocal<Integer>(){ @Override protected Integer initialValue(){ return 100; } }; public void save(int money){ account.set(account.get()+money); } public int getAccount(){ return account.get(); } }

Note: ThreadLocal and synchronization mechanism 
a.ThreadLocal and synchronization mechanism are both to solve the access conflict problem of the same variable in multiple threads. 
b. The former adopts the method of "space for time", while the latter adopts the method of "time for space"

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324816919&siteId=291194637