一,Java内存模型
Java内存模型规定了所有的内存变量都存储在主内存中。每条线程中还有自己的工作内存,线程的工作内存中保存了被该线程所使用到的变量(这些变量是从主内存中拷贝而来)。线程对变量的所有操作(读取,赋值)都必须在工作内存中进行。不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均通过主内存来完成
基于这种模型的多线程就会出现很多问题,多线程的---------脏读数据
举例说明:
i=123++;
现在有同时2个线程执行这段代码,加入初始值为123,那么有两个线程正常情况下得到的值,正常的值是125,
但是呢,初始时,两个线程分别读取i的值存入到各自所在的工作内存中,然后线程1进行加1操作,然后把i的最新值124写入到内存。此时线程2的工作内存当中的i的值还是123,进行加1操作,i的值还是为124,然后线程2把i的值写入内存。
最终结果i的值是124,而不是125.这就是-----------------缓存一致性的问题。这种被多个线程访问的变量为共享变量。
volatile 保证了变量的修改让所有的线程可见 阻止指令排序 相对的来说
volatile 当一个共享变量被volatile修饰的时候呢,它会保证修改的值会立即被更新到内存,当有其他线程需要读取时,它会去内存中读取新值。
sync 能够解决 可见性 原子性 volatile只能解决可见性 if()操作
例如,当第一个线程比较之后,进来修改了值,第二个比较之后,拿到的值还是原来的值,变量没有原子化
大多数多线程问题都是由CAS操作引起的。compare and set 先比较,后修改。
如何解决多线程问题呢:
1,线程封闭:final 不要线程之间共享变量
2,堆栈 栈封闭 比如 方法内部声明 修改 这样不会溢出
3,ThreadLocal 线程绑定
Synchronized用于线程之间的数据共享(使变量或者代码块在某一时刻只能被一个线程访问),是一种以延长访问时间来换取线程安全性的策略。
ThreadLocal则用于线程之间的数据隔离(为每一个线程都提供了变量的副本),是一种以空间来换取线程安全性的策略.
ThreadLocal的使用:
package fiveSteps; /** * @author liugang * @create 2018/12/10 23:53 **/ public class MainLocalTest { private static ThreadLocal<LocalTest> threadLocal = new ThreadLocal<>(); public static void main(String[] args) { LocalTest local = new LocalTest(); new Thread(){ @Override public void run() { for (;;){ threadLocal.set(local); LocalTest l = threadLocal.get(); l.setNum(20); System.out.println(Thread.currentThread().getName()+"--------------"+threadLocal.get().getNum()); Thread.yield(); } } }.start(); new Thread(){ @Override public void run() { for (;;){ threadLocal.set(local); LocalTest l = threadLocal.get(); l.setNum(30); System.out.println(Thread.currentThread().getName()+"--------------"+threadLocal.get().getNum()); Thread.yield(); } } }.start(); } }
package fiveSteps; /** * @author liugang * @create 2018/12/10 23:51 **/ public class LocalTest { public int getNum() { return num; } public void setNum(int num) { this.num = num; } private int num; }
原文地址:https://www.cnblogs.com/fuckingPangzi/p/10099965.html