zoukankan      html  css  js  c++  java
  • java-多线程与锁

    概述:

      多线程的使用,锁,线程池,更多的锁。

    1:多线程的使用。

      1.1:使用多线程需要保证:原子性,可见性,有序性。

      1.2:启动多线程的方法:(不做 多余赘述,写两种常见的方式)

        继承Thread类,重写run方法。

        实现Runnable接口,重写run方法。

      1.3:这里引出一个方法  join()。(一个执行先后的方法)

        假设开启了两个线程T1,T2,如果同时 start 之后T1,T2的执行顺序比较随机,如果在T2的 run 方法中写上T1.join(),那么就是说T2在T1执行完之后执行。

    2:高并发保证线程安全:锁。

      2.1:分类:synchronized(内置锁),lock。

      2.2:区别:lock需要unlock方法手动解锁,synchronized在执行完锁的部分或者异常就是释放锁。

      2.3:对于synchronized的使用。(解决的是高并发情况多线程公用一个变量引起的线程安全问题)

        2.3.1:同步方法。

    public class Test {
    
        /**
         * 同步方法
         * 说明:锁的对象:这个类,即Test类,也叫this锁。
         */
        public synchronized void syncTest() {
            // TODO Auto-generated method stub
    
        }
    }

        2.3.2:同步代码块。

    public class Test {
        
        private Object object = new Object();
    
        /**
         * 同步代码块
         * 说明:锁的对象:
         *         这个类,即Test类,
         *         也可以的一对象。
         * 以下两种皆可
         */
        public void syncTest() {
            //锁的类
            synchronized (this) {
                
            }
            //锁的对象
            synchronized (object) {
                
            }
        }
    }

        2.3.3:静态同步代码。

    public class Test {
        
        /**
         * 同步代码块
         * 说明:锁的对象:
         *         这个类(即Test类)的字节码文件,
         */
        public static void syncTest() {
            synchronized (Test.class) {
                
            }
        }
    }

      2.4:延伸的概念。

        2.4.1:修饰词 threadLocal(解决的是多线程之间公用的变量隔离出来使用,不影响其他线程)

          概述:将共享变量私有化。具体使用网上有很多的帖子。

        2.4.2:修饰词 volatile (修改变量,快速写入主内存)

          解释说明:首先了解共享内存模型(jmm),即一个变量在内存中存于主内存,还有一块虚拟的私有内存(虚拟的,不存在的)。

            内存结构是我们常说的 jvm。

            普通变量:修改的是自己私有内存的变量,然后再同步到主内存中。

            被volatile 修饰的变量:1:会快速的被写入主内存,然后其他线程使用时候直接从主内存中拿取。我的理解是不是volatile 修饰的变量

                      一直操作的是主内存中的呢?(没有看过源码进行深入的研究,只是一个疑问,不过不太影响对这个的理解)

                      2:volatile 可以禁止指令重排序(指令重排是cpu为了提高程序的执行性能的一种方法)。

          对比synchronized:

            1:优点,volatile 不会造成线程阻塞,性能方面要由于锁。volatile 可以禁止指令重排序。

            2:缺点,volatile 是可以保证可见性,有序性,但是不能保证原子性,所以不能取代synchronized。

            总结:volatile 是轻量级的synchronized,如果有对变量进行操作等场景使用synchronized。

          使用场景:

            单例模式是个典型的应用。

            说明:变量需要volition修饰,变量的构造赋值部分是用synchronized修饰的,目的是T1进入了synchronized部分之后,

               如果对象还未完全构建成功,那么T2进入,发现判断的对象不为null,这样会存在问题。

        2.4.3:wait(),notify(),notifyAll()应用。(wait让线程进入等待状态,notify唤醒当前线程,notifyAll唤醒所以线程)

          假设场景 :假如对一个共享变量,T1进行set值,T2进行get值。我们要保证:T2 get值时候,变量里面要有值的,T1 set值时候变量是无指的。

               T1与T2中使用wait(),notify()组合。

          对比 sleep() :sleep等待多长时间继续执行,不会释放锁。wait会释放锁。

    3:线程池。

      3.1:为何使用线程池:

        频繁的以1的描述方式开启线程,关闭线程,很消耗性能,所以引入线程池。

      3.2:线程池种类:

        newCachedThreadPool:缓存线程池

        newFixedThreadPool:定长线程池

      3.3:spring项目中的应用。(自定义一个线程池)

    @Configuration
    @EnableAsync    //开启异步调用
    public class Test {
        
        /**
         * 详细的参数解释可参见,里面有相应的线程池参数配置规则
         * https://www.cnblogs.com/waytobestcoder/p/5323130.html
         * @return
         */
        @Bean("pool1")
        public Executor threadPool1() {
            ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
            //线程核心数目
            threadPoolTaskExecutor.setCorePoolSize(10);
            //核心线程,超时是否关闭,一般缓存线程池默认60S,其他线程池设置的是0S,我们默认这个也是60S
            threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
            //最大线程数
            threadPoolTaskExecutor.setMaxPoolSize(10);
            //配置队列大小
            threadPoolTaskExecutor.setQueueCapacity(50);
            //配置线程池前缀,相当于@Bean("pool1")已经指定了使用的线程池名称
    //        threadPoolTaskExecutor.setThreadNamePrefix("pool1");
            //配置拒绝策略
            threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
            //数据初始化
            threadPoolTaskExecutor.initialize();
            return threadPoolTaskExecutor;
        }
        
    }
    @Async("pool1")
    public void test(){
            
    }

      如果调用了test(),就是使用了线程池pool1。

    4:更多的锁

      4.1:乐观锁,悲观锁,重入锁,自旋锁,分布式锁,CAS无锁

      CAS概述:三个值,初始值,期望值,新值。如果初始值=期望值,那么初始值=新值,否则代表有其他线程已经改了,再重新取值对比。

      

  • 相关阅读:
    Mongodb--基础(连接,增删改查,数据类型)
    [初识]使用百度AI接口,图灵机器人实现简单语音对话
    python--Websocket实现, 加密 sha1,base64
    Flask系列10-- Flask请求上下文源码分析
    python--partial偏函数
    Flask系列09--Flask中WTForms插件,及自定义验证器
    Flask系列08--Flask中flask_session, redis插件
    Flask系列07--Flask中的CBV, 蓝图的CBV
    Flask系列06--(中间件)Flask的特殊装饰器 before_request,after_request, errorhandler
    Flask系列05--Flask的配置config
  • 原文地址:https://www.cnblogs.com/dblog/p/12158259.html
Copyright © 2011-2022 走看看