-
如何判断程序有没有可能出现线程安全问题,主要有以下三个条件:
在多线程程序中 + 有共享数据 + 多条语句操作共享数据
解决思路:
可以从第3点"多条语句操作共享数据"入手,既然是在这多条语句操作数据过程中出现了问题
那我们可以把有可能出现问题的代码都包裹起来,一次只让一个线程来执行 -
同步与异步
-
同步:体现了排队的效果,同一时刻只能有一个线程独占资源,其他没有权利的线程排队。
坏处就是效率会降低,不过保证了安全。
-
异步:体现了多线程抢占资源的效果,线程间互相不等待,互相抢占资源。
坏处就是有安全隐患,效率要高一些。
-
-
写法:
synchronized (锁对象){undefined
需要同步的代码(也就是可能出现问题的操作共享数据的多条语句);
} -
前提
同步效果的使用有两个前提:
- 前提1:同步需要两个或者两个以上的线程(单线程无需考虑多线程安全问题)
- 前提2:多个线程间必须使用同一个锁(我上锁后其他人也能看到这个锁,不然我的锁锁不住其他人,就没有了上锁的效果)
-
特点:
- synchronized同步关键字可以用来修饰代码块,称为同步代码块,使用的锁对象类型任意,但注意:必须唯一!
- synchronized同步关键字可以用来修饰方法,称为同步方法
- 同步的缺点是会降低程序的执行效率,但我们为了保证线程的安全,有些性能是必须要牺牲的
- 但是为了性能,加锁的范围需要控制好,比如我们不需要给整个商场加锁,试衣间加锁就可以了
-
解决超卖—在循环语句里添加双重检测
双重检测 :入口加判断 if(可以进入的条件){共享的多条语句}
出口加判断—即为while循环的出口语句 if(结束执行的条件){break;}
if(进入的条件){共享语句} if(结束执行条件)break; -
解决重卖----同步代码块—在循环里
方法1:
-
创建唯一的锁对象----成员变量,如果是继承类需要加静态
-
解决的是重卖的问题 用synchronized () {}
-
创建锁对象---new一个 比如:Cat c = new Cat(); while(true){ synchronized (锁对象) { 双重检测 + 共享语句 }
方法2:
- 类名.class 字节码文件对象是唯一的锁对象
while(true){ synchronized (类名.class) { 双重检测 + 共享语句 }备注:
方法1--------实现类用的多
方法2--------继承类用的多
-
-
线程池
-
分类
- JDK自带注解
- 元注解
- 自定义注解
-
JDK自带注解
JDK注解的注解,就5个:
- @Override :用来标识重写方法
- @Deprecated标记就表明这个方法已经过时了,但我就要用,别提示我过期
- @SuppressWarnings(“deprecation”) 忽略警告
- @SafeVarargs jdk1.7出现,堆污染,不常用
- @FunctionallInterface jdk1.8出现,配合函数式编程拉姆达表达式,不常用
-
元注解
用来描述注解的注解,就5个:- @Target 注解用在哪里:类上、方法上、属性上等等
- @Retention 注解的生命周期:源文件中、字节码文件中、运行中
- @Inherited 允许子注解继承
- @documented 生成javadoc时会包含注解,不常用
- @Repeatable注解为可重复类型注解,可以在同一个地方多次使用,不常用
-
自定义注解
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)//小括号里相当于方法的参数 现在这个表示 注解只能加在方法上 @Target({ElementType.METHOD,ElementType.TYPE})//规定多个位置 //3.通过@Retention注解标记自定义注解的生命周期 @Retention(RetentionPolicy.RUNTIME) //1.定义自定义注解 @interface Rice{ //5.我们可以给注解进行工能增强 ---- 添加注解的属性 // int age();//给自定义注解添加了一个普通属性age 类型为int int age() default 0;//给自定义注解的普通属性赋予默认值0 //String value();//定义一个特殊属性 value,类型是String String value() default "Lemon";//定义特殊属性 并且给特殊属性赋予默认值 } //4.定义一个类 用来测试自定义注解 //@Rice class TestAnno{ // @Rice 报错了 String name; // @Rice(age=10) //@Rice报错 //@Rice // @Rice("Apple") @Rice(age=10,value="orange") public void eat(){ System.out.println("eat方法"); } }单例程序单例模式最重要的是确保对象只有一个。
简单来说,保证一个类在内存中的对象就一个。
package cn.tedu.design; 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.提供本类的构造方法 并将其私有化 private MySingle(){ } //2.创建本类对象 并将其私有化 //4.2 由于静态资源只能调用静态资源 所以single对象也需要设置为静态 //5.为什么加私有 是因为避免在主方法中被类名直接调用属性值 private static MySingle single = new MySingle(); //3.提供公共的访问方式,返回刚刚创建好的对象 //4.1 为了不通过对象 直接调用本方法 需要将本方法设置为静态 public static MySingle getSingle(){ return single; } }



