线程(6),volatile关键字,对象等待集

本文深入探讨了Java并发编程中的Volatile关键字如何确保内存可见性,避免编译器优化带来的线程安全问题。同时,讲解了对象等待集的概念,通过Wait、Notify和NotifyAll方法解决线程间资源竞争,提升程序运行效率。

1.volatile

  • 作用:保持内存的可见性
    例如
import java.util.Scanner;

public class Test11 {
    static class Cou {
        private int flag = 0;
    }

    public static void main(String[] args) {

        Cou  c = new Cou();

        Thread t1 = new Thread() {
            @Override
            public void run() {
                while (c.flag == 0) {

                }
                System.out.println("循环结束");
            }
        };
        t1.start();

        Thread t2 = new Thread() {

            @Override
            public void run() {
                Scanner sc = new Scanner(System.in);
                System.out.println("随便输入一个不为0的整数");
                c.flag = sc.nextInt();
            }
        };
        t2.start();

    }
}

得到的结果为

随便输入一个不为0的整数
1


并不会输出线程结束

  • 在线程t1的while循环的比较操作中,先从内存中读取flag的值到cpu中,在cpu中比较flag这个值和0的相等关系
  • 但是编译器判定这个逻辑循环没有干啥事,只是频繁读取内存而已,于是进行了操作优化,只是第一次真正的从内存中读取了flag,其他时候不会从内存中读取,直接从cpu中得到这个数据,于是这个t1线程永远不会结束这个循环。这也就是我们常见的编译器优化导致的线程不安全

那木如何去解决这个问题,就需要我们的volatile关键字了,就是一个线程读,一个线程写的问题。

我们给falg加上volatile关键字。

import java.util.Scanner;

public class Test11 {
    static class Cou {
        private volatile int flag = 0;
    }

    public static void main(String[] args) {

        Cou  c = new Cou();

        Thread t1 = new Thread() {
            @Override
            public void run() {
                while (c.flag == 0) {

                }
                System.out.println("循环结束");
            }
        };
        t1.start();

        Thread t2 = new Thread() {

            @Override
            public void run() {
                Scanner sc = new Scanner(System.in);
                System.out.println("随便输入一个不为0的整数");
                c.flag = sc.nextInt();
            }
        };
        t2.start();

    }
}

得到的结果

随便输入一个不为0的整数
1
循环结束
  • 加了volatile关键字后,我们都这个flag的操作的每一次读取都在内存上读取,就不会存在刚才所讲到的问题了。

2 .对象等待集

  • 我们知道线程是的操作是抢占式执行的,我们假想有多个线程在等待一个cpu给提供资源,但是其中线程x抢cpu抢的快,但是当前cpu并没有那个可以给x提供的资源,又因为这个x不停的抢cpu,导致其他线程不能进入到cpu中,因此会影响到程序的运行效率。

为了解决这个问题,我们引入了对象等待集,也就是wait,notify,notifyAll三个关键字,要和synchronized一起用

  • wait 如果cpu中没有满足这个线程执行的资源时候,让这个线程等待
  • notify 当cpu中的条件成熟的时候,通知指定的线程工作,唤醒一个线程
  • notifyAll 是一个唤醒所有线程,让这些线程去竞争一把锁
import java.util.Scanner;

public class Test12 {
    public static void main(String[] args) {

        Object o = new Object();

        Thread t1 = new Thread() {
            @Override
            public void run() {
                synchronized (o) {
                        try {
                            System.out.println("wait开始");
                            o.wait();
                            System.out.println("wait结束");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                    }
                }
            }
        };
        t1.start();

        Thread t2 = new Thread() {
            @Override
            public void run() {
                Scanner scanner = new Scanner(System.in);
                System.out.println("任意输出一个属,执行notify");
                int x = scanner.nextInt();
                synchronized (o) {
                    System.out.println("notify 开始");
                    o.notify();
                    System.out.println("notify 结束");
                }
            }
        };
        t2.start();
    }
}
任意输出一个属,执行notify
1
notify 开始
notify 结束
wait结束

Process finished with exit code 0
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值