002--volatile 关键字-内存可见性

话题一:多线程的3种创建方式

Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用三种方式来创建线程,如下所示:
1)继承Thread类创建线程
2)实现Runnable接口创建线程
3)使用Callable和Future创建线程


话题二:wait和notify的理解与使用

  • 案例分析wait和notify

  • wait和notify知识补充:首先要理解notify()和wait(),因为这两个方法本来就不属于Thread类,而是属于最底层的object基础类的,也就是说不光是Thread,每个对象都有notify和wait的功能,为什么

因为他们是用来操纵锁的,而每个对象都有锁,锁是每个对象的基础,既然锁是基础的,那么操纵锁的方法当然也是最基础了.


话题三:同样是线程休眠:wait(),sleep(),suspend()有什么区别呢?

  • wait:让当前线程阻塞,同时又“积极”地等待条件发生改变,这一点很关键,sleep和suspend无法做到.
    1)因为我们有时候需要通过同步(synchronized)的帮助来防止线程之间的冲突,而一旦使用同步,就要锁定对象,也就是获取对象锁,其它要使用该对象锁的线程都只能排队等着,等到同步方法或者同步块里的程序全部运行完才有机会.在同步方法和同步块中,无论sleep()还是suspend()都不可能自己被调用的时候解除锁定,他们都霸占着正在使用的对象锁不放

    2) 而wait却可以,它可以让同步方法或者同步块暂时放弃对象锁,而将它暂时让给其它需要对象锁的人(这里应该是程序块,或线程)用,这意味着可在执行wait()期间调用线程对象中的其他同步方法!在其它情况下(sleep啊,suspend啊),这是不可能的.

    3) 但是注意我前面说的,只是暂时放弃对象锁,暂时给其它线程使用,我wait所在的线程还是要把这个对象锁收回来的!

  • sleep:

  • suspend:


话题四:wait()暂时放弃对象锁后,如何将对象锁收回来?

  • 第一种方法,限定借出去的时间.在wait()中设置参数,比如wait(1000),以毫秒为单位,就表明我只借出去1秒中,一秒钟之后,我自动收回:wait(long timeout);
  • 第二种方法,让借出去的人通知我,他用完了,要还给我了.这时,我马上就收回来:notify();
  • PS:.哎,假如我设了1小时之后收回,别人只用了半小时就完了,那怎么办呢?靠!当然用完了就收回了,还管我设的是多长时间啊!

话题五:线程的可用方法展示

  • notify():通知
  • wait():等待
  • run():执行
002--volatile 关键字-内存可见性
查看Thread线程的方法

话题六:synchronized和volatile?

1.volatile问题引出

// 老师演示的时候,有一个问题,虽然子线程falg=true,但是main线程打印依然是false!但是在我的JDK上没有重现这一个现象
public class TestVolatile {
    public static void main(String[] args) throws Exception {
        // 1.创建一个线程
        MyThreadA myThreadA = new MyThreadA();
        new Thread(myThreadA).start();
        new Thread(myThreadA).start();
        
        // 2.mian主线程
        while(true){
            if (myThreadA.flag) {
                System.out.println("-------------主线程flag:"+myThreadA.flag);
                Thread.sleep(1000);
            }else{
                System.out.println("*************主线程flag:"+myThreadA.flag);
                Thread.sleep(1000);
            }
        }
    }
}
class MyThreadA implements Runnable{
    public boolean flag = Boolean.FALSE;
    
    @Override
    public void run() {
        try {
            System.out.println("-----------自定义线程执行休眠1s");
            Thread.sleep(200);
            flag = Boolean.TRUE;
            System.out.println("-----------休眠结束flag:"+flag);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

2.synchronized(object){}代表什么含义?
- 只能由一个线程同时使用object
- 多线程时,先判断锁,有锁就要将后续线程阻塞挂起,直到下一次CPU重新给他进行任务分配
- 加锁的这种效率是最低的!但是又需要刷新数据(内存可见性的问题),怎么办?--volatile
- volatile可以保证多个线程在访问相同数据时候,数据是实时可见的(实时将缓存数据刷新到主存中)!


3.synchronized和volatile比较
- volatile对比于synchronized,是一种轻量级的同步策略!
- volatile不具备"互斥性",不能保证只有一个线程使用共享数据
- volatile不能保证变量的原子性


4.什么是原子性?

  i++ 的原子性问题:i++ 的操作实际上分为三个步骤“读-改-写”
  int i = 10;
  i = i++; //10

  int temp = i;
  i = i + 1;
  i = temp;
- 本身来说,i++不能将过程进行拆解,但是volatile不能保证原子性,如果在多线程下就会被拆开,数据的执行结果就会出错!