Java线程中的关键字和方法示例详解

 更新时间:2022年03月02日 10:38:34   作者:/少司命  
这篇文章主要介绍了Java有关线程中的关键字和方法,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

一、volatile关键字

1,volatile 能保证内存可见性

代码在写入 volatile 修饰的变量的时候

        改变线程工作内存中volatile变量副本的值

        将改变后的副本的值从工作内存刷新到主内存

代码在读取 volatile 修饰的变量的时候

        从主内存中读取volatile变量的最新值到线程的工作内存中

        从工作内存中读取volatile变量的副本

 static class Counter{
        public int flag = 0;
    }
    
    public static void main(String[] args) {
        Counter counter = new Counter();
        Thread t1 = new Thread(){
            @Override
            public void run() {
                while (counter.flag == 0){
 
                }
                System.out.println("循环结束");
            }
        };
        t1.start();
        Thread t2 = new Thread(){
                Scanner scanner = new Scanner(System.in);
                System.out.println("请输入一个整数:");
                counter.flag = scanner.nextInt();
        t2.start();

 

预期的结果是:

线程1会先进入循环状态,线程2读取一个用户输入的整数。随着用户的输入一个非0的整数之后,线程1就会终止。

实际效果:

线程2输入完毕后,线程1循环并未结束

2,编译器优化问题

线程1的核心代码中,循环其实啥也没干,反复快速的执行循环条件中的比较操作。

        先从内存中读取flag的值到CPU中

        在CPU中比较这个值和0的关系

编译器判定这个逻辑中循环没有干啥事,只是频繁的读取内存而已,于是编译器就把读内存的操作优化了,第一次把内存中的数据督读到CPU之后,后序的内存并不是真正的从内存中读,而是直接从刚在的CPU中读数据

编译器认为flag没有改动,其实只是在当前线程中没有改动,编译器就不能感知到其他的线程对flag进行了修改

static class Counter{
        public  volatile  int flag = 0;
    }
 
    public static void main(String[] args) {
        Counter counter = new Counter();
        Thread t1 = new Thread(){
            @Override
            public void run() {
                while (counter.flag == 0){
                }
                System.out.println("循环结束");
            }
        };
        t1.start();
        Thread t2 = new Thread(){
                Scanner scanner = new Scanner(System.in);
                System.out.println("请输入一个整数:");
                counter.flag = scanner.nextInt();
        t2.start();

加了volatile之后,对这个内存的读取操作肯定是从内存中来读

不加volatile的时候,读取操作可能不是从内存中读取,从CPU上读取旧值,这都是不确定的

volatile 和 synchronized 有着本质的区别.

synchronized 能够保证原子性, volatile 保证的是内存可见性

synchronized 既能保证原子性, 也能保证内存可见性.

二、wait 和 notify

由于线程之间是抢占式执行的, 因此线程之间执行的先后顺序难以预知. 但是实际开发中有时候我们希望合理的协调多个线程之间的执行先后顺序

1,wait()方法

wait 做的事情:

使当前执行代码的线程进行等待. (把线程放到等待队列中)

释放当前的锁

满足一定条件时被唤醒, 重新尝试获取这个锁.

wait 要搭配 synchronized 来使用. 脱离 synchronized 使用 wait 会直接抛出异常.

wait 结束等待的条件:

其他线程调用该对象的 notify 方法.

wait 等待时间超时 (wait 方法提供一个带有 timeout 参数的版本, 来指定等待时间).

其他线程调用该等待线程的 interrupted 方法, 导致 wait 抛出 InterruptedException 异常.

public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        synchronized (object){
            System.out.println("等待前");
            object.wait();
            System.out.println("等待后");
        }
    }

就相当于一个人去ATM上取钱,发现ATM中没钱,然后阻塞等待(不参与后续锁的竞争)——wait

等到银行的工作人员来送钱,你可以取钱了——notify

2,notify()方法

notify 方法是唤醒等待的线程.

        方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。

        如果有多个线程等待,则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 "先来后到")

        在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行 完,也就是退出同步代码块之后才会释放对象锁。

 public static void main(String[] args) {
        Object locker = new Object();
 
        Thread t1 = new Thread(){
            @Override
            public void run() {
                synchronized (locker){
                    while (true){
                        System.out.println("wait开始");
                        try {
                            locker.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("wait结束");
                    }
                }
            }
        };
        t1.start();
        Thread t2 = new Thread(){
                Scanner scanner = new Scanner(System.in);
                System.out.println("输入一个整数,继续执行");
                int num = scanner.nextInt();
                    System.out.println("notify开始");
                    locker.notify();
                    System.out.println("notify结束");
        t2.start();
    }

 3,notifyAll()方法

notify方法只是唤醒某一个等待线程.

使用notifyAll方法可以一次唤醒所有的等待线程.

到此这篇关于Java有关线程中的关键字和方法的文章就介绍到这了,更多相关java线程关键字内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中异常Exception和捕获以及自定义异常详解

    Java中异常Exception和捕获以及自定义异常详解

    在工作过程中,我们常常需要在合适的地方抛出合适的异常,除了java自带的一些异常,我们可以在项目中定制自己的异常,并且全局捕获它,下面这篇文章主要给大家介绍了关于Java中异常Exception和捕获以及自定义异常的相关资料,需要的朋友可以参考下
    2023-05-05
  • Spring Boot 实现字段唯一校验功能(实例代码)

    Spring Boot 实现字段唯一校验功能(实例代码)

    这篇文章主要介绍了Spring Boot 实现字段唯一校验,实现代码很简单,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • SpringBoot项目启动时初始化操作常见的几种方式

    SpringBoot项目启动时初始化操作常见的几种方式

    这篇文章主要介绍了SpringBoot项目启动时初始化操作常见的几种方式,这些方法可以帮助开发者在服务启动时自动执行必要的初始化操作,需要的朋友可以参考下
    2025-02-02
  • SpringSecurity中的UserDetails和UserDetailsService接口详解

    SpringSecurity中的UserDetails和UserDetailsService接口详解

    这篇文章主要介绍了SpringSecurity中的UserDetails和UserDetailsService接口详解,UserDetailsService 在 Spring Security 中主要承担查询系统内用户、验证密码、封装用户信息和角色权限,需要的朋友可以参考下
    2023-11-11
  • java实现图片的上传与展示实例代码

    java实现图片的上传与展示实例代码

    这篇文章主要给大家介绍了关于java实现图片的上传与展示的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-12-12
  • 使用proguard对maven构建的springboot项目进行混淆方式

    使用proguard对maven构建的springboot项目进行混淆方式

    文章介绍了如何使用ProGuard对Maven构建的Spring Boot项目进行混淆,并解决混淆后可能遇到的版本兼容性问题和类名冲突问题,主要步骤包括下载高版本的ProGuard、配置POM文件、添加ProGuard配置文件、修改Spring Boot启动文件以避免类名冲突
    2024-11-11
  • java中数组的相关知识小结(推荐)

    java中数组的相关知识小结(推荐)

    下面小编就为大家带来一篇java中数组的相关知识小结(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-07-07
  • java多线程之并发工具类CountDownLatch,CyclicBarrier和Semaphore

    java多线程之并发工具类CountDownLatch,CyclicBarrier和Semaphore

    这篇文章主要为大家介绍了java并发工具类CountDownLatch,CyclicBarrier和Semaphore ,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • 解决try-catch捕获异常信息后Spring事务失效的问题

    解决try-catch捕获异常信息后Spring事务失效的问题

    这篇文章主要介绍了解决try-catch捕获异常信息后Spring事务失效的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • Spring Boot整合FTPClient线程池的实现示例

    Spring Boot整合FTPClient线程池的实现示例

    这篇文章主要介绍了Spring Boot整合FTPClient线程池的实现示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-12-12

最新评论