Javaweb之线程2

volatile

import java.util.Scanner;

public class ThreadDemo {
    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.println("循环结束");
            }
        };
        t1.start();
        Thread t2 = new Thread() {
            @Override
            public void run() {
                Scanner scanner = new Scanner(System.in);
                System.out.println("亲输入一个整数");
                counter.flag = scanner.nextInt();


            }
        };
        t2.start();
    }
}

在这里插入图片描述
这个代码本来的预期效果是输入整数后循环结束,但是当输入后,并没有结束。

其实,这是编译器优化的问题。开始,线程1 反复对循环条件进行比较操作(先从内存中读取flag的值到CPU,在CPU中比较这个值和0的相等关系),因为从CPU寄存器上读取数据比内存中读数据还是快很多的,编译器判定这个判断相等操作就是不断从内存中读取内存而已,于是编译器就进行了优化,在第一次吧数据从内存读取到CPU后,之后就直接从CPU中读取数据,所以编译器认为flag没有改动,就出现了误判。

这样的优化策略就是“内存可见性”;
如果优化生效,内存不可见,不生效,内存才是可见的。
在这里插入图片描述
在这里插入图片描述
但是当在flag前加上volatile后,就可以保证内存可见性了。

但这个和原子性是没有关系的,对于一个线程读,一个线程写,得用volatile解决,但是对于两个线程修改同一变量时,还得用加锁去解决。

notify和wait

对象等待集 (本质让程序员有一定手段去干预线程调度)
主要还是因为抢占式执行的问题

wait方法:当操作条件不成熟就等待(必须在sychronized内部使用)
notify方法:当条件成熟,通知指定线程来工作。(也必须在sychronized里使用)

wait步骤:
1.释放锁
2.等待通知
3.收到通知,重新获取锁,继续往下执行
其中,前两步在wait中是原子的,避免竞态条件问题。
在这里插入图片描述
调用锁的对象和wait的对象必须是对应的。

import java.util.Scanner;

public class ThreadDemo4 {
    public static void main(String[] args) {
        Object locker = new Object();
        Thread t1 = new Thread() {
            @Override
            public void run() {
                synchronized (locker) {
                    while (true) {
                        try {
                            System.out.println("wait开始");
                            locker.wait();
                            System.out.println("wait结束");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }

            }
        };
        t1.start();
        Thread t2 = new Thread() {
            @Override
            public void run() {
                Scanner scanner = new Scanner(System.in);
                System.out.println("输入整数");
                int num = scanner.nextInt();
                synchronized (locker) {
                    System.out.println("notify开始");
                    locker.notify();
                    System.out.println("notify结束");
                }
            }
        };
        t2.start();
    }
}

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章