java 多线程关键字,java 线程安全关键字

  java 多线程关键字,java 线程安全关键字

  00-1010 I volatile关键字1、volatile能保证内存可见性2、编译器优化问题2、wait和notify1、wait()方法2、notify()方法3、notifyAll()方法

  

目录

 

  00-1010编写易变修改变量时的代码

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

  刷新从工作内存到主内存的已更改副本的值。

  当代码读取volatile修改的变量时

  将可变变量的最新值从主内存读入线程的工作内存。

  从工作内存中读取易失性变量的副本

  静态类计数器{ public int flag=0;}公共静态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将读取用户输入的一个整数。当用户输入一个非零整数时,线程1将终止。

  实际效果:

  在输入线程2之后,线程1的循环没有完成。

  在00-1010 thread 1的核心代码中,循环实际上什么都不做,循环条件中的比较操作被反复快速执行。

  首先,从内存中读取标志的值到CPU中

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

  编译器决定这个逻辑中的循环除了频繁读取内存之外什么也不做,所以编译器优化了读取内存的操作。第一次读取内存中的数据到CPU后,后续的内存并没有真正从内存中读取,而是直接从刚才的CPU中读取数据。

  编译器认为该标志没有被更改,但它只在当前线程中,因此编译器无法感知其他线程修改了该标志。

  静态类计数器{ public volatile int flag=0;}公共静态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中读取旧值,不确定。

  te>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线程关键字内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

 

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: