java大数据学习第十七天------同步锁 注解 单例模式之一饿汉式

同步锁

  1. 如何判断程序有没有可能出现线程安全问题,主要有以下三个条件:

    ​ 在多线程程序中 + 有共享数据 + 多条语句操作共享数据

    ​ 解决思路:

    ​ 可以从第3点"多条语句操作共享数据"入手,既然是在这多条语句操作数据过程中出现了问题
    那我们可以把有可能出现问题的代码都包裹起来,一次只让一个线程来执行

  2. 同步与异步

    • 同步:体现了排队的效果,同一时刻只能有一个线程独占资源,其他没有权利的线程排队。

      坏处就是效率会降低,不过保证了安全。

    • 异步:体现了多线程抢占资源的效果,线程间互相不等待,互相抢占资源。

      坏处就是有安全隐患,效率要高一些。

synchronized同步关键字

  1. 写法:

    synchronized (锁对象){undefined
    需要同步的代码(也就是可能出现问题的操作共享数据的多条语句);
    }

  2. 前提

    同步效果的使用有两个前提:

    • 前提1:同步需要两个或者两个以上的线程(单线程无需考虑多线程安全问题)
    • 前提2:多个线程间必须使用同一个锁(我上锁后其他人也能看到这个锁,不然我的锁锁不住其他人,就没有了上锁的效果)
  3. 特点:

    • synchronized同步关键字可以用来修饰代码块,称为同步代码块,使用的锁对象类型任意,但注意:必须唯一!
    • synchronized同步关键字可以用来修饰方法,称为同步方法
    • 同步的缺点是会降低程序的执行效率,但我们为了保证线程的安全,有些性能是必须要牺牲的
    • 但是为了性能,加锁的范围需要控制好,比如我们不需要给整个商场加锁,试衣间加锁就可以了
  4. 解决超卖—在循环语句里添加双重检测

    双重检测 :入口加判断 if(可以进入的条件){共享的多条语句}

    ​ 出口加判断—即为while循环的出口语句 if(结束执行的条件){break;}

    if(进入的条件){共享语句}
    if(结束执行条件)break;
    
  5. 解决重卖----同步代码块—在循环里

    方法1:

    • 创建唯一的锁对象----成员变量,如果是继承类需要加静态

    • 解决的是重卖的问题 用synchronized () {}

    • 创建锁对象---new一个  比如:Cat c = new Cat();
      while(true){
          synchronized (锁对象) {
              双重检测 + 共享语句
      }			
      

    方法2:

    • 类名.class 字节码文件对象是唯一的锁对象
    while(true){
        synchronized (类名.class) {
            双重检测 + 共享语句
    }			
    

    备注:

    ​ 方法1--------实现类用的多

    ​ 方法2--------继承类用的多

  6. 线程池

注解

  1. 分类

    • JDK自带注解
    • 元注解
    • 自定义注解
  2. JDK自带注解

    JDK注解的注解,就5个:

    • @Override :用来标识重写方法
    • @Deprecated标记就表明这个方法已经过时了,但我就要用,别提示我过期
    • @SuppressWarnings(“deprecation”) 忽略警告
    • @SafeVarargs jdk1.7出现,堆污染,不常用
    • @FunctionallInterface jdk1.8出现,配合函数式编程拉姆达表达式,不常用
  3. 元注解
    用来描述注解的注解,就5个:

    • @Target 注解用在哪里:类上、方法上、属性上等等
    • @Retention 注解的生命周期:源文件中、字节码文件中、运行中
    • @Inherited 允许子注解继承
    • @Documented 生成javadoc时会包含注解,不常用
    • @Repeatable注解为可重复类型注解,可以在同一个地方多次使用,不常用
  4. 自定义注解

    package cn.tedu.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**  四   本类用于完成自定义注解*/
    public class TestAnnotation {
    
    }
    
    
    
    //2.通过 @Target 注解标记自定义注解可以使用的位置,要写在自定义注解的上边
    //@Target(ElementType.METHOD)//小括号里相当于方法的参数  现在这个表示 注解只能加在方法上
    /*3.通过元注解 @Target 规定自定义注解可以使用的位置
    * 我们使用 "ElementType.静态常量" 的方式来指定自定义注解具体可以家在什么位置
    * 而且,值可以写多个,格式:@Target({ElementType.xxx1,ElementType.xxx2})*/
    @Target({ElementType.METHOD,ElementType.TYPE})//规定多个位置
    //3.通过@Retention注解标记自定义注解的生命周期
    /* 4. 通过元注解@Retention 规定自定义注解的声明周期
    * 我们使用 "RetentionPolicy.静态常量" 的方式来指定自定义注解的生命周期
    * 注意:值只能写一个:SOURCE CLASS RUNTIME 3选1*/
    @Retention(RetentionPolicy.RUNTIME)
    
    //1.定义自定义注解
    /*1.首先注意:注解定义的语法与java不同,
     * 2.定义自定义注解的格式:  @interface + 注解名
     * */
    @interface Rice{
        //5.我们可以给注解进行工能增强  ----  添加注解的属性
        /*6. int age(); 不是方法的定义,而是给自定义注解添加了一个age属性*/
       // int age();//给自定义注解添加了一个普通属性age 类型为int
        int age() default 0;//给自定义注解的普通属性赋予默认值0
        /*7.注解中还可以添加特殊属性value,
        *特殊属性的定义方式和普通属性一样,主要是使用方式不同
        *注意:特殊属性的名字必须叫value,但是类型不做限制
        *特殊属性也可以赋予默认值,格式与普通属性的赋值一样,不能简写
        * */
        //String value();//定义一个特殊属性 value,类型是String
        String value() default "Lemon";//定义特殊属性 并且给特殊属性赋予默认值
    }
    
    
    /*5.注解使用的格式:@注解名*/
    //4.定义一个类 用来测试自定义注解
    //@Rice
    class TestAnno{
        /*测试1:分别给TestAnno类 name属性 eat方法上都添加Rice注解
        * 结论: 属性上的注解报错了,说明自定义的注解可以加在什么位置,由@Target决定*/
       // @Rice  报错了
        String name;
        /*测试2 : 当我们给Rice注解添加了一个属性age以后,@Rice注解使用时会直接报错
        * 结论: 当注解没有定义属性时,可以直接使用
        *      当注解定义了属性以后 必须给属性赋值,格式:@Rice(age = 10)   必须写全不能简写*/
       // @Rice(age=10)
        /*测试3 : 给age属性赋予默认值以后 可以直接使用@Rice注解
        * 不需要给age属性赋值 因为age属性已经有默认值0了*/
        //@Rice报错
        /*测试4.给Rice注解添加了特殊属性value后,也必须给属性赋值
        * 只不过特殊属性赋值时可以简写成: @Rice("Apple")*/
        /*测试5. 如果特殊属性也赋予了默认值,那么可以直接使用这个注解
        * 如果想要给注解的所有属性赋值,每条赋值都不能简写*/
        //@Rice
       // @Rice("Apple")
        @Rice(age=10,value="orange")
        public void eat(){
            System.out.println("eat方法");
        }
    
    }
    

    单例程序

    单例模式最重要的是确保对象只有一个。

    简单来说,保证一个类在内存中的对象就一个。

    package cn.tedu.design;
    /** 五  本类用于实现单例设计模式 方案1  饿汉式*/
    public class Singleton1 {
        public static void main(String[] args) {
           // new MySingle();
            MySingle s1 = MySingle.getSingle();
            MySingle s2 = MySingle.getSingle();
            System.out.println(s1==s2);//true
            System.out.println(s1);
            System.out.println(s2);
    
    
        }
    }
    
    
    //0.创建自己的单例程序
    class MySingle{
    
    
        //1.提供本类的构造方法 并将其私有化
        /*1.构造方法私有化的目的:为了防止外界随意调用,创建本类对象*/
        private MySingle(){ }
    
        //2.创建本类对象 并将其私有化
        //4.2 由于静态资源只能调用静态资源 所以single对象也需要设置为静态
        //5.为什么加私有 是因为避免在主方法中被类名直接调用属性值
        private static MySingle single = new MySingle();
    
        //3.提供公共的访问方式,返回刚刚创建好的对象
        //4.1 为了不通过对象 直接调用本方法 需要将本方法设置为静态
        public static MySingle getSingle(){
            return single;
        }
    
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值