关于多线程的一些补充

线程八锁问题

线程八锁问题是指判断多线程的同步监视器是哪个类的对象(知道锁的是谁)
那么线程八锁问题经典解法就是改变两个打印数据方法的类型,看多线程情况下是如何输出的关于多线程的一些补充
(1)两个普通的同步方法:谁先拿到锁谁先执行
关于多线程的一些补充
关于多线程的一些补充
(2)在sendSms()中增加线程休眠:谁先拿到谁先执行
关于多线程的一些补充
关于多线程的一些补充
(3)新增普通方法:普通方法不受锁的影响,所以它先执行
关于多线程的一些补充
关于多线程的一些补充
关于多线程的一些补充
(4)两个普通同步方法,两个不同的对象:谁的执行时间短谁先拿到锁,谁先执行
关于多线程的一些补充
关于多线程的一些补充
(5)修改发短信为静态同步方法:static代表Class,类加载时执行,所以锁是Phone.class对象,不同的锁,谁时间短谁先拿到谁执行
关于多线程的一些补充
关于多线程的一些补充
(6)修改两个方法均为静态同步方法:锁都是Phone.class对象,是同一把锁,谁先拿到谁执行

关于多线程的一些补充
(7)两个方法一个静态一个非静态,两个Phone对象:不同的锁对象,谁的时间短谁先执行
关于多线程的一些补充
(8)两个静态同步方法,两个Phone对象:锁都是Phone.class对象,是同一把锁,谁先拿到谁执行
关于多线程的一些补充
线程八锁的关键在于,非静态方法的锁默认为this,静态方法的锁默认为class的实例,并且某个时刻内,只能有一个线程持有锁。

Volatile关键字以及JMM(Java Memory Model)

什么是JMM(Java内存模型)?
Java内存模型,是一种不存在的概念,JMM的一些同步的约定:
(1)线程解锁前:必须把共享数据刷回到主存中(因为线程是把主存中的共享数据拷贝一份到自己的工作内存中进行操作的)
(2)线程加锁前:必须把主存中的最新的数据读取到线程自己的工作内存中

JAVA内存交互的八种操作,虚拟机实现必须保证每个操作都是原子的,是不可分的(对于double、long类型,在store、read和write操作在某些平台允许例外)

  1. lock(锁定):作用于主内存的变量,把一个变量标识为线程独占状态。
  2. unlock(解锁):作用于主内存变量,把一个处于锁定状态的变量释放出来,释放后的变量才能被其它的线程锁定。
  3. read(读取):把主内存中变量的值读取出来,以便之后加载到工作内存。
  4. load(载入):将读取到的变量数据载入到工作内存中。
  5. use(使用):将工作内存中的数据用执行引擎进行计算,每当虚拟机遇到要使用变量的值就会进行这个指令
  6. assign(赋值):将在执行引擎中计算完后得到的变量值赋值给工作内存中的变量副本
  7. store(存储):将工作内存中的值读取出来并进行保存
  8. write(写入):将保存的变量的值重新写回到主存
    关于多线程的一些补充
    关于多线程的一些补充

volatile不能保证原子性,即解决不了线程安全问题,用volatile修饰的变量会同时被多个线程操作。
volatile保证内存可见性,即主存中的任何变动会立马通知给线程以达到数据同步。
volatile由于内存屏障的缘故可以禁止指令重排序,