多平台统一管理软件接口,如何实现多平台统一管理软件接口
227
2022-08-24
Java线程中的关键字和方法示例详解
目录一、volatile关键字1,volatile能保证内存可见性2,编译器优化问题二、wait和notify1,wait()方法2,notify()方法 3,notifyAll()方法
一、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.FdXgMcKPprintln("循环结束");
}
};
t1.start();
Thread t2 = new Thread(){
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个整数:");
counter.flag = scanner.nextInt();
t2.start();
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 和 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("等待后");
}
}
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 {
FdXgMcKP 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方法可以一次唤醒所有的等待线程.
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~