Java多线程【状态与安全问题】(上)

简介: Java多线程【状态与安全问题】

🍎一.多线程状态


🍇1.1多线程的状态形式


线程状态 说明
NEW 安排了工作, 还未开始行动
RUNNABLE 可工作的. 又可以分成正在工作中和即将开始工作
BLOCKED 这几个都表示排队等着其他事情
WAITING 这几个都表示排队等着其他事情
TIMED_WAITING 这几个都表示排队等着其他事情
TERMINATED 工作完成了


1.NEW状态:安排了工作, 还未开始行动

public class Test {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
        });
        System.out.println(thread.getState());
    }
}

55581073f64c4980871b1b3f748450c9.png

2.RUNNABLE:可工作的. 又可以分成正在工作中和即将开始工作

public class Test {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            while (true){
                //这里面不能有人任务,这样才会显示是就绪状态
            }
        });
        thread.start();
        System.out.println(thread.getState());
    }
}


d0b7e7032d0c42aeb5bcc5abceffd4fa.png

3.TERMINATED:工作完成了


操作系统线程已经执行完毕,线程已经销毁了,但是Thread对象还存在,获取到的状态

public class Test {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
                System.out.println("我滴任务完成啦!");
        });
        thread.start();
        Thread.sleep(500);
        System.out.println(thread.getState());
    }
}

82058f07a0be4508a7afefc8c88b869f.png

4.TIMED_WAITING:代码调用了sleep或者join(超时时间)

public class Test {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            while (true) {
                System.out.println("我在等一会");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        Thread.sleep(500);
        System.out.println(thread.getState());
    }
}

d324b5eb794a48d6829c65c7260cab0f.png


BLOCKED,WAITING|这两个状态我们后续会将


🍇1.2状态转化分布图

b43358a940b6459f845206a2be6f5e69.png



🍎二.多线程的安全问题


🍇2.1线程安全问题的概念


如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线


程安全的。

如果多线程环境下代码运行的结果是不符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程不安全的。


🍇2.2线程不安全示例


假设我们设置一个count初始值为0,我们使用两个线程同时并且每条线程执行5万次,这样我们的预期count结果为10万,接下来我们来演示一下看看两个线程并发是否安全


public class Test {
   static class Count{
        public int count = 0;
        public void sum(){
            count++;
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Count count = new Count();
        Thread thread1 = new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                count.sum();
            }
        });
        Thread thread2 = new Thread(()->{
            for (int i = 0; i < 50000; i++) {
               count.sum();
            }
        });
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(count.count);
    }
}

0487ac6714134edfb65476856c029e90.pngd56f2f270938464b9634bebfaca0c706.png



我们发现count执行的结果并不是10万,而是5万-10万之间的随机数,这是什么原因呢?接下来我来帮助大家了解一下为什么在对对同一数据进行并发线程不安全

原子性

什么是原子性?

我们把一段代码想象成一个房间,每个线程就是要进入这个房间的人。如果没有任何机制保证,A进入房间之后,还没有出来;B 是不是也可以进入房间,打断 A 在房间里的隐私。这个就是不具备原子性的。

那我们应该如何解决这个问题呢?是不是只要给房间加一把锁,A 进去就把门锁上,其他人是不是就进不来了。这样就保证了这段代码的原子性了。有时也把这个现象叫做同步互斥,表示操作是互相排斥的。

一条 java 语句不一定是原子的,也不一定只是一条指令比如刚才我们看到的 n++,其实是由三步操作组成的:

1. 从内存把数据读到 CPU

2. 进行数据更新

3. 把数据写回到 CPU不保证原子性会给多线程带来什么问题如果一个线程正在对一个变量操作,中途其他线程插入进来了,如果这个操作被打断了,结果就可能是错误的。


可见性

可见性指, 一个线程对共享变量值的修改,能够及时地被其他线程看到.线程之间的共享变量存在 主内存 (Main Memory).每一个线程都有自己的 “工作内存” (Working Memory) .当线程要读取一个共享变量的时候, 会先把变量从主内存拷贝到工作内存, 再从工作内存读取数据.当线程要修改一个共享变量的时候, 也会先修改工作内存中的副本, 再同步回主内存.由于每个线程有自己的工作内存, 这些工作内存中的内容相当于同一个共享变量的 “副本”. 此时修改线程1 的工作内存中的值, 线程2 的工作内存不一定会及时变化.


cfa6b058e6294da7b53a8185db50b65c.png

情况一:


03536b43070e482b9c0684b29cb76112.png


情况二:


11080047e6554d0ca953b6ca0af7de0d.png


情况三:

f35f53b45e424a57abbfe63eb286425c.png


情况四:



6d8a192c4cd24f908e588b07b340a8b2.png


重排序问题:


6f414f748b734ee888e9216ae93dba97.png

相关文章
|
22小时前
|
Java
Java一分钟:线程协作:wait(), notify(), notifyAll()
【5月更文挑战第11天】本文介绍了Java多线程编程中的`wait()`, `notify()`, `notifyAll()`方法,它们用于线程间通信和同步。这些方法在`synchronized`代码块中使用,控制线程执行和资源访问。文章讨论了常见问题,如死锁、未捕获异常、同步使用错误及通知错误,并提供了生产者-消费者模型的示例代码,强调理解并正确使用这些方法对实现线程协作的重要性。
9 3
|
22小时前
|
安全 算法 Java
Java一分钟:线程同步:synchronized关键字
【5月更文挑战第11天】Java中的`synchronized`关键字用于线程同步,防止竞态条件,确保数据一致性。本文介绍了其工作原理、常见问题及避免策略。同步方法和同步代码块是两种使用形式,需注意避免死锁、过度使用导致的性能影响以及理解锁的可重入性和升级降级机制。示例展示了同步方法和代码块的运用,以及如何避免死锁。正确使用`synchronized`是编写多线程安全代码的核心。
10 2
|
22小时前
|
安全 Java 调度
Java一分钟:多线程编程初步:Thread类与Runnable接口
【5月更文挑战第11天】本文介绍了Java中创建线程的两种方式:继承Thread类和实现Runnable接口,并讨论了多线程编程中的常见问题,如资源浪费、线程安全、死锁和优先级问题,提出了解决策略。示例展示了线程通信的生产者-消费者模型,强调理解和掌握线程操作对编写高效并发程序的重要性。
10 3
|
1天前
|
安全 Java
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第11天】在Java并发编程中,线程安全和性能优化是两个重要的主题。本文将深入探讨这两个方面,包括线程安全的基本概念,如何实现线程安全,以及如何在保证线程安全的同时进行性能优化。我们将通过实例和代码片段来说明这些概念和技术。
2 0
|
1天前
|
Java 调度
Java并发编程:深入理解线程池
【5月更文挑战第11天】本文将深入探讨Java中的线程池,包括其基本概念、工作原理以及如何使用。我们将通过实例来解释线程池的优点,如提高性能和资源利用率,以及如何避免常见的并发问题。我们还将讨论Java中线程池的实现,包括Executor框架和ThreadPoolExecutor类,并展示如何创建和管理线程池。最后,我们将讨论线程池的一些高级特性,如任务调度、线程优先级和异常处理。
|
1天前
|
安全 Java
【JAVA进阶篇教学】第十篇:Java中线程安全、锁讲解
【JAVA进阶篇教学】第十篇:Java中线程安全、锁讲解
|
1天前
|
安全 Java
【JAVA进阶篇教学】第六篇:Java线程中状态
【JAVA进阶篇教学】第六篇:Java线程中状态
|
1天前
|
缓存 Java
【JAVA进阶篇教学】第五篇:Java多线程编程
【JAVA进阶篇教学】第五篇:Java多线程编程
|
1天前
|
Java
【JAVA基础篇教学】第十二篇:Java中多线程编程
【JAVA基础篇教学】第十二篇:Java中多线程编程
|
2天前
|
安全 Java
java-多线程学习记录
java-多线程学习记录