企业网站包含的内容,北京市企业信用信息查询网,中国上海门户网,十大代理记账公司目录 volatile关键字
volatile保证内存可见性
代码示例
代码示例2-#xff08;volatile#xff09;
volatile不保证原子性
synchronized保证内存可见性
wait()和notify()
wait()方法
notify()
理解notify()和notifyAll()
wait和sleep的对比 volatile关键字
volati…
目录 volatile关键字
volatile保证内存可见性
代码示例
代码示例2-volatile
volatile不保证原子性
synchronized保证内存可见性
wait()和notify()
wait()方法
notify()
理解notify()和notifyAll()
wait和sleep的对比 volatile关键字
volatile保证内存可见性
volatile 修饰的变量, 能够保证 内存可见性. 代码在写入 volatile 修饰的变量的时候 改变线程工作内存中volatile变量副本的值 将改变后的副本的值从工作内存刷新到主内存 代码在读取 volatile 修饰的变量的时候 从主内存中读取volatile变量的最新值到线程的工作内存中 从工作内存中读取volatile变量的副本 加上 volatile , 强制读写内存. 速度是慢了, 但是数据变的更准确了。
代码示例
public class Demo13 {private static int isQuit0;public static void main(String[] args) {Thread t1new Thread(()-{while(isQuit0){}System.out.println(t1 退出);});t1.start();Thread t2new Thread(()-{System.out.println(请输入 isQuit:);Scanner scannernew Scanner(System.in);isQuitscanner.nextInt();});t2.start();}
}
运行结果 通过jconsole观察会看到线程t1处于RUNNABLE状态。 t1 读的是自己工作内存中的内容 . 当 t2 对 flag 变量进行修改 , 此时 t1 感知不到 flag 的变化 . 原因解释 1) load 读取内存中isQuit的值到寄存器中. 2)通过cmp 指令比较寄存器的值是否是0.决定是否要继续循环. 由于这个循环,循环速度飞快.短时间内,就会进行大量的循环.也就是进行大量的load和cmp 操作.此时,编译器/JVM就发现了虽然进行了这么多次load,但是 load 出来的结果都一样的.并且, load 操作又非常费时间,一次load花的时间相当于上万次cmp 了. 所以编译器就做了一个大胆的决定~~只是第一次循环的时候才读了内存.后续都不再读内存了,而是直接从寄存器中,取出isQuit的值了. 代码示例2-volatile
public class Demo13 {private static volatile int isQuit0;public static void main(String[] args) {Thread t1new Thread(()-{while(isQuit0){}System.out.println(t1 退出);});t1.start();Thread t2new Thread(()-{System.out.println(请输入 isQuit:);Scanner scannernew Scanner(System.in);isQuitscanner.nextInt();});t2.start();}
}
运行结果 代码示例3-sleep
public class Demo13 {private static int isQuit0;public static void main(String[] args) {Thread t1new Thread(()-{while(isQuit0){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println(t1 退出);});t1.start();Thread t2new Thread(()-{System.out.println(请输入 isQuit:);Scanner scannernew Scanner(System.in);isQuitscanner.nextInt();});t2.start();}
}
运行结果 volatile不保证原子性
代码示例
class Counter {volatile public int count 0;void increase() {count;}
}public class Demo13 {public static void main(String[] args) throws InterruptedException {final Counter counter new Counter();Thread t1 new Thread(() - {for (int i 0; i 50000; i) {counter.increase();}});Thread t2 new Thread(() - {for (int i 0; i 50000; i) {counter.increase();}});t1.start();t2.start();t1.join();t2.join();System.out.println(counter.count);}
}
运行结果 我们会发现加上volatile以后依旧不是线程安全的。
synchronized保证内存可见性
代码示例
class Counter {public int flag 0;
}public class Demo13 {public static void main(String[] args) {Counter counter new Counter();Thread t1 new Thread(() - {while (true) {synchronized (counter) {if (counter.flag ! 0) {break;}}}System.out.println(循环结束!);});Thread t2 new Thread(() - {Scanner scanner new Scanner(System.in);System.out.println(输入一个整数:);counter.flag scanner.nextInt();});t1.start();t2.start();}
}
运行结果 wait()和notify()
wait()方法
wait 做的事情: 使当前执行代码的线程进行等待. (把线程放到等待队列中) 释放当前的锁 满足一定条件时被唤醒, 重新尝试获取这个锁. wait 要搭配 synchronized 来使用. 脱离 synchronized 使用 wait 会直接抛出异常.
代码示例
public class Demo14 {public static void main(String[] args) throws InterruptedException {Object object new Object();synchronized (object) {System.out.println(wait 之前);// 把 wait 要放到 synchronized 里面来调用. 保证确实是拿到锁了的.object.wait();System.out.println(wait 之后);}}
} 运行结果 此时object就会一直进行wait当然我们肯定不想让程序一直等待下去下面将介绍notify()来唤醒它。
notify()
notify 方法是唤醒等待的线程. 方法notify()也要在同步方法或同步块中调用该方法是用来通知那些可能等待该对象的对象锁的其它线程对其发出通知notify并使它们重新获取该对象的对象锁。 如果有多个线程等待则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 先来后到)在notify()方法后当前线程不会马上释放该对象锁要等到执行notify()方法的线程将程序执行完也就是退出同步代码块之后才会释放对象锁。 代码示例
public class Demo15 {public static void main(String[] args) {Object object new Object();Thread t1 new Thread(() - {synchronized (object) {System.out.println(wait 之前);try {object.wait();
// object.wait(5000);//也可以指定等待时间后自动唤醒} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(wait 之后);}});Thread t2 new Thread(() - {try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized (object) {System.out.println(进行通知);object.notify();}});t1.start();t2.start();}
}
运行结果 notifyAll() notify方法只是唤醒某一个等待线程. 使用notifyAll方法可以一次唤醒所有的等待线程. 代码示例 class WaitTask implements Runnable {private Object locker;public WaitTask(Object locker) {this.locker locker;}Overridepublic void run() {synchronized (locker) {while (true) {try {System.out.println(wait 开始);locker.wait();System.out.println(wait 结束);} catch (InterruptedException e) {e.printStackTrace();}}}}
}
class NotifyTask implements Runnable {private Object locker;public NotifyTask(Object locker) {this.locker locker;}Overridepublic void run() {synchronized (locker) {System.out.println(notify 开始);locker.notifyAll();System.out.println(notify 结束);}}
}public class Demo16 {public static void main(String[] args) throws InterruptedException {Object locker new Object();Thread t1 new Thread(new WaitTask(locker));Thread t3 new Thread(new WaitTask(locker));Thread t4 new Thread(new WaitTask(locker));Thread t2 new Thread(new NotifyTask(locker));t1.start();t2.start();t3.start();Thread.sleep(5000);t4.start();}
} 运行结果 注意: 虽然是同时唤醒 3 个线程, 但是这 3 个线程需要竞争锁. 所以并不是同时执行, 而仍然是有先有后的执行. 理解notify()和notifyAll() notify 只唤醒等待队列中的一个线程 . 其他线程还是乖乖等着. notifyAll 一下全都唤醒, 需要这些线程重新竞争锁. wait和sleep的对比 唯一的相同点就是都可以让线程放弃执行一段时间. 1. wait 需要搭配 synchronized 使用 . sleep 不需要 . 2. wait 是 Object 的方法 sleep 是 Thread 的静态方法 .