java线程间的等待唤醒机制和volatile关键字
线程间的等待唤醒机制
Object类中
void wait(); 就是在其他线程调用此对象的notify()和notifyAll()方法前,导致当前线程等待。
void wait(long timeout); 就是在其他线程调用此对象的notify()和notifyAll()方法,或者超过指定的时间量前,导致当前线程等待
void notify(); 唤醒在此对象监视器上等待的单个线程
void notify(); 唤醒在此对象监视器上等待的所有线程
在某个线程方法中对wait()和notify()的调用必须指定一个object对象,而且该线程必须拥有该object对象的monitor。而获取对象monitor最简单的办法就是,在对象上使用synchronized关键字。当调用wait()方法以后,该线程会释放掉对象锁,并进入sleep状态。而在其他线程调用notify()方法时,必须使用同一个object对象,notify()方法调用成功后,所在这个对象上的相应的等待线程将被唤醒。
wait()和sleep()的区别:
wait():一旦等待就会释放锁;可以设置等待时间量,也可以不设置时间量。
sleep():线程休眠后,不会释放锁;必须设置时间量
案例
public class MyTest {
public static void main(String[] args) {
MyObject myObject = new MyObject();
CharMyThread th1 = new CharMyThread(myObject);
NumThread th2 = new NumThread(myObject);
th1.start();
th2.start();
}
}
class MyObject{
int flag=1;
}
class CharMyThread extends Thread{
private MyObject obj;
public CharMyThread(MyObject obj) {
this.obj = obj;
}
@Override
public void run() {
for(int i='A';i<='Z';i++){
synchronized (obj){
if(obj.flag!=2){
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print((char)i);
obj.flag=1;
obj.notify();
}
}
}
}
}
class NumMyThread extends Thread{
private MyObject obj;
public NumMyThread(MyObject obj) {
this.obj = obj;
}
@Override
public void run() {
for (int i = 1; i <= 52; i++) {
if(obj.flag!=1){
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print(i);
if(i%2==0){
obj.flag=2;
obj.notify();
}
}
}
}
结果是
volatile关键字
volatile关键字是解决内存可见性问题
java可见性
对于可见性,java提供了volatile关键字来保证可见性
当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值
而普通的共享变量不能保证可见性,因为普通共享变量被修饰之后,什么时候被写入主存时不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。
另外,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的刷新到主存当中,因此可以保证可见性。
voliatile关键字: 当多个线程进行操作共享数据时,可以保证内存中的数据可见。相较于synchronized是一种较为轻量级的同步策略,但是由于锁不同,对于多线程,不是一种互斥关系;不能保证变量状态的“原子性操作”。
public class MyTest3 {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread th = new Thread(myRunnable);
th.start();
while (true){
if(myRunnable.isFlag()){
System.out.println("进来了");
break;
}
}
}
}
class MyRunnable implements Runnable{
volatile boolean flag=false;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag=true;
System.out.println("run方法里改了flag的值:"+flag);
}
}
结果是