Home Java javaTutorial 【java】Why use synchronization? About thread synchronization (7 ways)

【java】Why use synchronization? About thread synchronization (7 ways)

Aug 06, 2018 am 11:58 AM

Why use synchronization?

Java allows multi-threaded concurrency control. When multiple threads operate a shareable resource variable at the same time (such as adding, deleting, modifying, and checking data),
will lead to inaccurate data. , conflict with each other, so a synchronization lock is added to avoid being called by other threads before the thread completes the operation,
thereby ensuring the uniqueness and accuracy of the variable.

1. Synchronization method
It is a method modified by the synchronized keyword.
Since every object in Java has a built-in lock, when a method is modified with this keyword,
the built-in lock will protect the entire method. Before calling this method, you need to obtain the built-in lock, otherwise it will be blocked.

Code such as:
public synchronized void save(){}

Note: The synchronized keyword can also modify a static method. At this time, if the static method is called, the entire Class

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

Code such as:

   synchronized(object){ 
    }
Copy after login

Note: Synchronization is a high-cost method operation, so synchronized content should be minimized.
Usually there is no need to synchronize the entire method, just use synchronized code blocks to synchronize key codes.
Code example:

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();
        }

    }
Copy after login

3. Use special domain variables (volatile) to achieve thread synchronization

a. The volatile keyword is the domain Variable access provides a lock-free mechanism,
b. Using volatile to modify a domain is equivalent to telling the virtual machine that the domain may be updated by other threads,
c. Therefore, it must be recalculated every time the domain is used, Instead of using the value in the register
d.volatile does not provide any atomic operations, nor can it be used to modify final type variables
For example:
In the above example, just add in front of account Modify volatile to achieve thread synchronization.
Code example:

      //只给出要修改的代码,其余代码与上同
        class Bank {
            //需要同步的变量加上volatile
            private volatile int account = 100;

            public int getAccount() {
                return account;
            }
            //这里不再需要synchronized 
            public void save(int money) {
                account += money;
            }
        }
Copy after login

Note: The non-synchronization problem in multi-threading mainly occurs in reading and writing the domain. If the domain itself avoids this problem, there is no need to modify the operation. domain methods.

Use final fields, lock-protected fields and volatile fields to avoid asynchronous problems.
4. Use reentrancy locks to achieve thread synchronization

A new java.util.concurrent package has been added in JavaSE5.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 synchronized methods and blocks, and extends its capabilities

ReenreantLock Commonly used methods of the class are:

ReentrantLock(): Create a ReentrantLock instance
lock(): Obtain the lock
unlock(): Release the lock
Note: There is another option for ReentrantLock() Create a fair lock construction method, but because it can greatly reduce program running efficiency, it is not recommended to use
For example:
Based on the above example, the rewritten code is:
Code example:

//只给出要修改的代码,其余代码与上同
        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();
                }
                
            }
        }
Copy after login

Note: Regarding the selection of Lock object and synchronized keyword:

a. It is best not to use either, and use a mechanism provided by the java.util.concurrent package.
It can help users deal with all lock-related codes.
B. If the synchronized keyword can meet the needs of the user, use synchronized, because it can simplify the code
C. If you need more advanced features, use the ReentrantLock class. At this time, pay attention to release the lock in time, otherwise Deadlock will occur, usually the lock is released in the finally code
​The copies of this variable are independent of each other, so that each thread can modify its own copy of the variable at will without affecting other threads.
Common methods of ThreadLocal class

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

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

//只改Bank类,其余代码与上同
        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();
            }
        }
Copy after login

注:ThreadLocal与同步机制
a.ThreadLocal与同步机制都是为了解决多线程中相同变量的访问冲突问题。
b.前者采用以"空间换时间"的方法,后者采用以"时间换空间"的方法

6.使用阻塞队列实现线程同步

前面5种同步方式都是在底层实现的线程同步,但是我们在实际开发当中,应当尽量远离底层结构。
使用javaSE5.0版本中新增的java.util.concurrent包将有助于简化开发。
本小节主要是使用LinkedBlockingQueue来实现线程的同步
LinkedBlockingQueue是一个基于已连接节点的,范围任意的blocking queue。
队列是先进先出的顺序(FIFO),关于队列以后会详细讲解~

LinkedBlockingQueue 类常用方法
LinkedBlockingQueue() : 创建一个容量为Integer.MAX_VALUE的LinkedBlockingQueue
put(E e) : 在队尾添加一个元素,如果队列满则阻塞
size() : 返回队列中的元素个数
take() : 移除并返回队头元素,如果队列空则阻塞

代码实例:
实现商家生产商品和买卖商品的同步

【java】Why use synchronization? About thread synchronization (7 ways)

 1 package com.xhj.thread;
 2 
 3 import java.util.Random;
 4 import java.util.concurrent.LinkedBlockingQueue;
 5 
 6 /**
 7  * 用阻塞队列实现线程同步 LinkedBlockingQueue的使用
 8  * 
 9  * @author XIEHEJUN
10  * 
11  */
12 public class BlockingSynchronizedThread {
13     /**
14      * 定义一个阻塞队列用来存储生产出来的商品
15      */
16     private LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();
17     /**
18      * 定义生产商品个数
19      */
20     private static final int size = 10;
21     /**
22      * 定义启动线程的标志,为0时,启动生产商品的线程;为1时,启动消费商品的线程
23      */
24     private int flag = 0;
25 
26     private class LinkBlockThread implements Runnable {
27         @Override
28         public void run() {
29             int new_flag = flag++;
30             System.out.println("启动线程 " + new_flag);
31             if (new_flag == 0) {
32                 for (int i = 0; i < size; i++) {
33                     int b = new Random().nextInt(255);
34                     System.out.println("生产商品:" + b + "号");
35                     try {
36                         queue.put(b);
37                     } catch (InterruptedException e) {
38                         // TODO Auto-generated catch block
39                         e.printStackTrace();
40                     }
41                     System.out.println("仓库中还有商品:" + queue.size() + "个");
42                     try {
43                         Thread.sleep(100);
44                     } catch (InterruptedException e) {
45                         // TODO Auto-generated catch block
46                         e.printStackTrace();
47                     }
48                 }
49             } else {
50                 for (int i = 0; i < size / 2; i++) {
51                     try {
52                         int n = queue.take();
53                         System.out.println("消费者买去了" + n + "号商品");
54                     } catch (InterruptedException e) {
55                         // TODO Auto-generated catch block
56                         e.printStackTrace();
57                     }
58                     System.out.println("仓库中还有商品:" + queue.size() + "个");
59                     try {
60                         Thread.sleep(100);
61                     } catch (Exception e) {
62                         // TODO: handle exception
63                     }
64                 }
65             }
66         }
67     }
68 
69     public static void main(String[] args) {
70         BlockingSynchronizedThread bst = new BlockingSynchronizedThread();
71         LinkBlockThread lbt = bst.new LinkBlockThread();
72         Thread thread1 = new Thread(lbt);
73         Thread thread2 = new Thread(lbt);
74         thread1.start();
75         thread2.start();
76 
77     }
78 
79 }
Copy after login

【java】Why use synchronization? About thread synchronization (7 ways)

注:BlockingQueue定义了阻塞队列的常用方法,尤其是三种添加元素的方法,我们要多加注意,当队列满时:

  add()方法会抛出异常

  offer()方法返回false

  put()方法会阻塞

7.使用原子变量实现线程同步

需要使用线程同步的根本原因在于对普通变量的操作不是原子的。

那么什么是原子操作呢?
原子操作就是指将读取变量值、修改变量值、保存变量值看成一个整体来操作
即-这几种行为要么同时完成,要么都不完成。
在java的util.concurrent.atomic包中提供了创建了原子类型变量的工具类
使用该类可以简化线程同步。
其中AtomicInteger 表可以用原子方式更新int的值,可用在应用程序中(如以原子方式增加的计数器),
但不能用于替换Integer;可扩展Number,允许那些处理机遇数字类的工具和实用工具进行统一访问。
AtomicInteger类常用方法:
AtomicInteger(int initialValue) : 创建具有给定初始值的新的AtomicInteger
addAddGet(int dalta) : 以原子方式将给定值与当前值相加
get() : 获取当前值
代码实例:
只改Bank类,其余代码与上面第一个例子同

【java】Why use synchronization? About thread synchronization (7 ways)

 1 class Bank {
 2         private AtomicInteger account = new AtomicInteger(100);
 3 
 4         public AtomicInteger getAccount() {
 5             return account;
 6         }
 7 
 8         public void save(int money) {
 9             account.addAndGet(money);
10         }
11     }
Copy after login

【java】Why use synchronization? About thread synchronization (7 ways)

补充--原子操作主要有:
  对于引用变量和大多数原始变量(long和double除外)的读写操作;
  对于所有使用volatile修饰的变量(包括long和double)的读写操作。

 相关文章:

关于Java线程同步和同步方法的详解

详解Java多线程编程中的线程同步方法

The above is the detailed content of 【java】Why use synchronization? About thread synchronization (7 ways). For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Roblox: Bubble Gum Simulator Infinity - How To Get And Use Royal Keys
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Nordhold: Fusion System, Explained
4 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Mandragora: Whispers Of The Witch Tree - How To Unlock The Grappling Hook
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1673
14
PHP Tutorial
1278
29
C# Tutorial
1257
24
Is the company's security software causing the application to fail to run? How to troubleshoot and solve it? Is the company's security software causing the application to fail to run? How to troubleshoot and solve it? Apr 19, 2025 pm 04:51 PM

Troubleshooting and solutions to the company's security software that causes some applications to not function properly. Many companies will deploy security software in order to ensure internal network security. ...

How do I convert names to numbers to implement sorting and maintain consistency in groups? How do I convert names to numbers to implement sorting and maintain consistency in groups? Apr 19, 2025 pm 11:30 PM

Solutions to convert names to numbers to implement sorting In many application scenarios, users may need to sort in groups, especially in one...

How to simplify field mapping issues in system docking using MapStruct? How to simplify field mapping issues in system docking using MapStruct? Apr 19, 2025 pm 06:21 PM

Field mapping processing in system docking often encounters a difficult problem when performing system docking: how to effectively map the interface fields of system A...

How does IntelliJ IDEA identify the port number of a Spring Boot project without outputting a log? How does IntelliJ IDEA identify the port number of a Spring Boot project without outputting a log? Apr 19, 2025 pm 11:45 PM

Start Spring using IntelliJIDEAUltimate version...

How to elegantly obtain entity class variable names to build database query conditions? How to elegantly obtain entity class variable names to build database query conditions? Apr 19, 2025 pm 11:42 PM

When using MyBatis-Plus or other ORM frameworks for database operations, it is often necessary to construct query conditions based on the attribute name of the entity class. If you manually every time...

How to safely convert Java objects to arrays? How to safely convert Java objects to arrays? Apr 19, 2025 pm 11:33 PM

Conversion of Java Objects and Arrays: In-depth discussion of the risks and correct methods of cast type conversion Many Java beginners will encounter the conversion of an object into an array...

E-commerce platform SKU and SPU database design: How to take into account both user-defined attributes and attributeless products? E-commerce platform SKU and SPU database design: How to take into account both user-defined attributes and attributeless products? Apr 19, 2025 pm 11:27 PM

Detailed explanation of the design of SKU and SPU tables on e-commerce platforms This article will discuss the database design issues of SKU and SPU in e-commerce platforms, especially how to deal with user-defined sales...

How to use the Redis cache solution to efficiently realize the requirements of product ranking list? How to use the Redis cache solution to efficiently realize the requirements of product ranking list? Apr 19, 2025 pm 11:36 PM

How does the Redis caching solution realize the requirements of product ranking list? During the development process, we often need to deal with the requirements of rankings, such as displaying a...

See all articles