zoukankan      html  css  js  c++  java
  • java的多线程学习,第三记

    一,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;
    
    
    }
  • 相关阅读:
    MongoDB数据库新建数据库用户
    Grafana部署
    k8s ingress及ingress controller
    Rabbitmq如何安装插件
    RabbitMQ手册之rabbitmq-plugins
    RabbitMQ运行在Docker容器中
    K8S资源限制
    System类
    Runtime类
    StringBuffer类
  • 原文地址:https://www.cnblogs.com/fuckingPangzi/p/10099965.html
Copyright © 2011-2022 走看看