【JavaEE】--多线程(初阶)3
- 游戏开发
- 2025-09-19 08:57:02

文章目录 6.volatile 关键字6.1 volatile能保证内存可见性6.1.1 CPU层面6.1.2 Java层面 6.2 volatile保证有序性6.3 volatile不保证原子性 7. wait 和 notify7.1 wait()方法和notify()方法7.3 notifyAll()方法7.4 wait() 和 sleep() 的对比(面试题) 6.volatile 关键字 public class Demo_601 { static int flg = 0; public static void main(String[] args) { Thread t1 = new Thread(()->{ System.out.println(Thread.currentThread().getName() + "线程启动"); while (flg == 0){ //不停的循环。处理任务。 } System.out.println(Thread.currentThread().getName() + "线程退出"); },"t1"); t1.start(); Thread t2 = new Thread(()->{ System.out.println(Thread.currentThread().getName() + "线程启动"); Scanner scanner = new Scanner(System.in); System.out.println("请输入一个非零的整数"); flg = scanner.nextInt(); System.out.println(Thread.currentThread().getName() + "线程退出"); }, "t2"); t2.start(); } }
输出结果:
t2线程正常结束,并且已经修改了flg变量的值,但是t1没有结束,整个进程也没有结束,结果不及预期,线程安全问题产生。
问题产生的原因: 对于线程t1来说,只是比较flg这个变量的值,从来都没有修改过,所以CPU认为,这个值永远也不会改变,从而也不会重新从内存中读取值。
为了提高运行效率这个值一般存在寄存器或CPU的缓存中。
在Java层面我们叫这块内存是寄存器,在JVM层面我们叫这块内存是工作内存。
在多线程的环境下,就会出现我们看到的这个问题,一个线程修改了另一个线程无法感知到的变量。
6.1 volatile能保证内存可见性 6.1.1 CPU层面MESI(缓存一致性协议),可以理解为一种通知机制。 当所有的处理器没有修改共享变量时,各自的处理器只读取自已缓存中的值,从而提升效率。
当某一个处理器往主内存中写回数据的时候,让缓存中的值失效,通知其他处理器从主内存中重新获取新的值。
6.1.2 Java层面内存屏障:作用是保证指令执行的先后顺序,从而保证内存可见性。 为变量加上volatile关键字进行修饰之后的输出结果:
6.2 volatile保证有序性用volatile修饰过的变量,由于前后有内存屏障,保证了指令的执行顺序,也可以理解为告诉编译器,不要进行指令重排。
6.3 volatile不保证原子性volatile 和 synchronized 有着本质的区别.synchronized能够保证原⼦性,volatile保证的是内存可⻅性.
7. wait 和 notify wait 和 notify 是Object类中的方法,每个对象都可以调用这个方法作用:安排线程的执行顺序。join 和 wait 是两种不同的操作,join是Thread类中的方法,wait 和 notify 是Object 类中的方法。
7.1 wait()方法和notify()方法 public class Demo_602 { public static void main(String[] args) { Object locker = new Object(); Thread t1 = new Thread(()->{ while (true) { System.out.println("调用wait()之前...."); synchronized (locker){ try { locker.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } System.out.println("wait()唤醒之后..."); System.out.println("====================="); } }); Thread t2 = new Thread(()->{ while (true) { System.out.println("调用notify之前...."); synchronized (locker){ locker.notify(); } System.out.println("调用notify之后...."); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); t1.start(); t2.start(); } } 7.3 notifyAll()方法notify()唤醒一个线程notifyAlI()唤醒所有线程,全都再去竞争锁资源。
总结:
wait 和 notify 必须搭配synchronized 一起使用。wait 和 notify 使用的锁对象必须是同一个。notify 执行多少次都没有关系(即使没有线程在wait) 7.4 wait() 和 sleep() 的对比(面试题)其实理论上wait和sleep完全是没有可⽐性的,因为⼀个是⽤于线程之间的通信的,⼀个是让线程阻塞⼀段时间,唯⼀的相同点就是都可以让线程放弃执⾏⼀段时间.
当然为了⾯试的⽬的,我们还是总结下:
wait需要搭配synchronized使⽤.sleep不需要,join也不需要(join是类中的方法)。wait是Object的⽅法sleep是Thread的静态⽅法.【JavaEE】--多线程(初阶)3由讯客互联游戏开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“【JavaEE】--多线程(初阶)3”