java线程之线程安全

简介: java线程之线程安全

一、什么是线程安全

线程安全是多线程编程时的计算机程序代码中的一个概念。. 在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。

同一个资源,多个线程操作它的状态,会发生结果和期望不一致的情况.

二、举例

 
import lombok.Data;
 
@Data
public class UnsafeSwquence {
    private int value;
 
    public int getNest(){
        //value自增
        value++;
        //答应打印当前线程的名称及值
        System.out.println(Thread.currentThread().getName()+":"+value);
        return value;
    }
} 

1、单线程操作

结果总是100

 /**
     * 单线程
     */
    @Test
    void test01() {
        UnsafeSwquence unsafeSwquenc = new UnsafeSwquence();
        for (int i = 0; i < 100; i++) {
            unsafeSwquenc.getNest();
        }
        System.out.println(unsafeSwquenc.getValue());
    }
main:1
main:2
main:3
main:4
main:5
main:6
main:7
main:8
main:9
main:10
main:11
main:12
main:13
main:14
main:15
main:16
main:17
main:18
main:19
main:20
main:21
main:22
main:23
main:24
main:25
main:26
main:27
main:28
main:29
main:30
main:31
main:32
main:33
main:34
main:35
main:36
main:37
main:38
main:39
main:40
main:41
main:42
main:43
main:44
main:45
main:46
main:47
main:48
main:49
main:50
main:51
main:52
main:53
main:54
main:55
main:56
main:57
main:58
main:59
main:60
main:61
main:62
main:63
main:64
main:65
main:66
main:67
main:68
main:69
main:70
main:71
main:72
main:73
main:74
main:75
main:76
main:77
main:78
main:79
main:80
main:81
main:82
main:83
main:84
main:85
main:86
main:87
main:88
main:89
main:90
main:91
main:92
main:93
main:94
main:95
main:96
main:97
main:98
main:99
main:100
100

2、多线程操作

结果概率出现其他值

 /**
     * 多线程
     * @throws InterruptedException
     */
    @Test
    void test02() throws InterruptedException {
        UnsafeSwquence unsafeSwquence = new UnsafeSwquence();
        for (int i = 0; i < 100; i++) {
            //创建线程并启动
            new Thread(() -> {
                unsafeSwquence.getNest();
            }).start();
        }
        //等待线程自增结束
        Thread.sleep(1000);
        //打印自增结果
        System.out.println(unsafeSwquence.getValue());
    }
Thread-1:1
Thread-2:2
Thread-9:3
Thread-4:4
Thread-5:5
Thread-7:6
Thread-3:7
Thread-10:8
Thread-11:9
Thread-13:11
Thread-12:10
Thread-6:13
Thread-14:13
Thread-16:15
Thread-26:14
Thread-27:16
Thread-17:17
Thread-18:18
Thread-19:19
Thread-34:20
Thread-35:21
Thread-22:22
Thread-23:23
Thread-24:24
Thread-38:25
Thread-15:26
Thread-8:27
Thread-29:28
Thread-31:29
Thread-41:34
Thread-25:35
Thread-21:40
Thread-45:33
Thread-30:32
Thread-43:31
Thread-28:30
Thread-42:31
Thread-44:45
Thread-46:44
Thread-32:43
Thread-33:42
Thread-20:41
Thread-40:39
Thread-36:39
Thread-37:38
Thread-39:38
Thread-50:49
Thread-49:48
Thread-48:47
Thread-47:46
Thread-53:52
Thread-52:51
Thread-51:50
Thread-54:53
Thread-56:54
Thread-55:55
Thread-57:56
Thread-59:58
Thread-58:57
Thread-61:60
Thread-62:61
Thread-60:59
Thread-72:66
Thread-66:65
Thread-65:64
Thread-77:70
Thread-64:63
Thread-63:62
Thread-67:71
Thread-76:69
Thread-70:68
Thread-75:74
Thread-68:67
Thread-74:73
Thread-73:72
Thread-69:75
Thread-71:76
Thread-78:77
Thread-80:78
Thread-81:79
Thread-83:80
Thread-84:82
Thread-82:81
Thread-79:83
Thread-85:84
Thread-87:85
Thread-88:86
Thread-89:87
Thread-86:88
Thread-90:90
Thread-92:91
Thread-91:90
Thread-93:92
Thread-96:93
Thread-95:94
Thread-94:95
Thread-97:96
Thread-98:97
Thread-100:98
Thread-99:99
99

三、如何保证线程安全

java并发编程实战给的三种修复方式

1 不在线程之间共享改状态变量;
 
2 将状态变量修改为不可变的变量;
 
3 在访问状态变量时使用同步;

1、使用同步状态量,需改getNest方法,添加synchronized关键字(不推荐,性能不佳).

   public synchronized int getNest() {
        //value自增
        value++;
        //打印当前线程的名称及值
        System.out.println(Thread.currentThread().getName() + ":" + value);
        return value;
    }
Thread-1:1
Thread-2:2
Thread-9:3
Thread-4:4
Thread-6:5
Thread-5:6
Thread-7:7
Thread-8:8
Thread-10:9
Thread-12:10
Thread-3:11
Thread-11:12
Thread-14:13
Thread-13:14
Thread-16:15
Thread-17:16
Thread-29:17
Thread-30:18
Thread-20:19
Thread-33:20
Thread-22:21
Thread-23:22
Thread-24:23
Thread-25:24
Thread-26:25
Thread-15:26
Thread-27:27
Thread-28:28
Thread-44:29
Thread-45:30
Thread-19:31
Thread-18:32
Thread-37:33
Thread-48:34
Thread-38:35
Thread-49:36
Thread-39:37
Thread-40:38
Thread-32:39
Thread-41:40
Thread-53:41
Thread-42:42
Thread-54:43
Thread-43:44
Thread-46:45
Thread-47:46
Thread-52:47
Thread-31:48
Thread-51:49
Thread-57:50
Thread-50:51
Thread-58:52
Thread-34:53
Thread-21:54
Thread-59:55
Thread-60:56
Thread-36:57
Thread-35:58
Thread-63:59
Thread-62:60
Thread-61:61
Thread-56:62
Thread-55:63
Thread-65:64
Thread-64:65
Thread-67:66
Thread-66:67
Thread-68:68
Thread-69:69
Thread-70:70
Thread-71:71
Thread-72:72
Thread-74:73
Thread-73:74
Thread-75:75
Thread-76:76
Thread-77:77
Thread-78:78
Thread-79:79
Thread-81:80
Thread-80:81
Thread-82:82
Thread-83:83
Thread-84:84
Thread-85:85
Thread-86:86
Thread-87:87
Thread-88:88
Thread-89:89
Thread-91:90
Thread-90:91
Thread-92:92
Thread-93:93
Thread-94:94
Thread-95:95
Thread-96:96
Thread-97:97
Thread-98:98
Thread-99:99
Thread-100:100
100


2、使用原子类进行计数(推荐)

jdk提供的原子类

import java.util.concurrent.atomic.AtomicInteger;
 
@Data
public class UnsafeSwquence {
    private int value;
    private AtomicInteger num = new AtomicInteger(0);
 
    public synchronized int getNest() {
        //value自增
        value++;
        //打印当前线程的名称及值
        System.out.println(Thread.currentThread().getName() + ":" + value);
        return value;
    }
 
    public int getNestInteger() {
        //num
        num.incrementAndGet();
        //打印当前线程的名称及值
        System.out.println(Thread.currentThread().getName() + ":" + num.get());
        return num.get();
    }
}

测试

 /**
     * 多线程
     * @throws InterruptedException
     */
    @Test
    void test03() throws InterruptedException {
        UnsafeSwquence unsafeSwquence = new UnsafeSwquence();
        for (int i = 0; i < 100; i++) {
            //创建线程并启动
            new Thread(() -> {
                unsafeSwquence.getNestInteger();
            }).start();
        }
        //等待线程自增结束
        Thread.sleep(1000);
        //打印自增结果
        System.out.println(unsafeSwquence.getNum().get());
    }
Thread-1:1
Thread-2:2
Thread-3:3
Thread-4:4
Thread-5:5
Thread-6:6
Thread-7:7
Thread-8:8
Thread-9:9
Thread-10:10
Thread-11:11
Thread-13:12
Thread-12:13
Thread-14:14
Thread-15:15
Thread-16:16
Thread-17:17
Thread-18:18
Thread-19:19
Thread-20:20
Thread-21:21
Thread-22:22
Thread-23:23
Thread-24:24
Thread-25:25
Thread-27:26
Thread-26:27
Thread-29:28
Thread-31:29
Thread-30:30
Thread-28:31
Thread-33:32
Thread-32:33
Thread-35:34
Thread-34:35
Thread-37:36
Thread-39:37
Thread-36:38
Thread-40:39
Thread-38:40
Thread-42:41
Thread-41:42
Thread-44:43
Thread-43:44
Thread-46:45
Thread-47:46
Thread-45:47
Thread-48:48
Thread-50:49
Thread-49:50
Thread-51:51
Thread-52:52
Thread-53:53
Thread-54:54
Thread-55:55
Thread-56:56
Thread-57:57
Thread-58:58
Thread-59:59
Thread-60:60
Thread-61:61
Thread-62:62
Thread-63:63
Thread-64:64
Thread-65:65
Thread-66:66
Thread-67:67
Thread-68:68
Thread-69:69
Thread-70:70
Thread-71:71
Thread-72:72
Thread-73:73
Thread-74:74
Thread-76:75
Thread-75:76
Thread-77:77
Thread-79:78
Thread-78:79
Thread-81:80
Thread-82:81
Thread-80:82
Thread-83:83
Thread-84:84
Thread-85:85
Thread-86:86
Thread-87:87
Thread-88:88
Thread-89:89
Thread-90:90
Thread-91:91
Thread-93:92
Thread-94:93
Thread-95:94
Thread-92:95
Thread-96:96
Thread-97:97
Thread-98:98
Thread-100:99
Thread-99:100
100

示例用到的依赖

    <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.2</version>
        </dependency>

目录
相关文章
|
1天前
|
监控 Java 调度
Java并发编程:深入理解线程池
【6月更文挑战第26天】在Java并发编程的世界中,线程池是提升应用性能、优化资源管理的关键组件。本文将深入探讨线程池的内部机制,从核心概念到实际应用,揭示如何有效利用线程池来处理并发任务,同时避免常见的陷阱和错误实践。通过实例分析,我们将了解线程池配置的策略和对性能的影响,以及如何监控和维护线程池的健康状况。
7 1
|
1天前
|
存储 缓存 Java
老程序员分享:Java并发编程:线程池的使用
老程序员分享:Java并发编程:线程池的使用
|
1天前
|
Java 数据库连接 调度
Java多线程,对锁机制的进一步分析
Java多线程,对锁机制的进一步分析
|
1天前
|
Java
Java多线程notifyAll()方法
Java多线程notifyAll()方法
|
2天前
|
存储 设计模式 并行计算
CopyOnWriteArrayList:深入理解Java中的线程安全List原理和应用
CopyOnWriteArrayList:深入理解Java中的线程安全List原理和应用
|
2天前
|
Java 测试技术 开发者
Java并发编程:深入理解线程池
本文将带领读者深入了解Java中的线程池,探索其内部机制、使用场景以及如何有效地利用线程池来提高程序的性能和可维护性。我们将通过实例演示如何创建和配置线程池,并讨论常见的并发模式和最佳实践。文章旨在为开发者提供实用的线程池应用知识,帮助他们在面对多线程编程挑战时,能够设计出更加高效和稳定的系统。
|
2天前
|
安全 Java 开发者
如何在Java中实现线程安全的单例模式
如何在Java中实现线程安全的单例模式
|
3天前
|
缓存 监控 安全
深入理解Java中的线程池和并发编程
深入理解Java中的线程池和并发编程
|
3天前
|
设计模式 安全 Java
如何在Java中实现线程安全的单例模式
如何在Java中实现线程安全的单例模式
|
1天前
|
存储 测试技术
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试
9 0
【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试