1 同步锁
把有可能出现问题的代码包起来,一次只让一个线程执行。通过sychronized关键字实现同步。
当多个对象操作共享数据时,可以使用同步锁解决线程安全问题。
1.1 synchronized
synchronized(对象){
需要同步的代码;
}
1.2 特点
1、 前提1,同步需要两个或者两个以上的线程。
2、 前提2,多个线程间必须使用同一个锁。
3、 同步的缺点是会降低程序的执行效率, 为了保证线程安全,必须牺牲性能。
4、 可以修饰方法称为同步方法,使用的锁对象是this。
5、 可以修饰代码块称为同步代码块,锁对象可以任意。
1.3 改造
package seday13new;
public class Test4 {
public static void main(String[] args) {
Ticket2 t = new Ticket2();
Thread target = new Thread(t, "窗口1");
Thread target2 = new Thread(t, "窗口2");
Thread target3 = new Thread(t, "窗口3");
Thread target4 = new Thread(t, "窗口4");
target.start();
target2.start();
target3.start();
target4.start();
}
}
class Ticket2 implements Runnable {
private int tic = 100;
Object obj = new Object();
@Override
public void run() {
while (true) {
// 把有线程安全问题的代码,用同步关键字包起来
// 原理:用一个对象作为一把锁,给代码上锁,一个线程访问锁代码时,其他线程只能等待锁释放才能进来。
// 多线程间要使用同一把锁才可以真的把代码锁住实现线程安全。
// synchronized (new Object()) {//锁了不同对象
// synchronized (obj) {//锁了同一个对象
//synchronized (Ticket2.class) {//锁了本类,针对于静态
synchronized (this) {
if (tic > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(tic--);
}
}
}
}
}
2 单例设计模式
2.1 概念
单例模式可以说是大多数开发人员在实际中使用最多的,常见的Spring默认创建的bean就是单例模式的。
单例模式有很多好处,比如可节约系统内存空间,控制资源的使用。
其中单例模式最重要的是确保对象只有一个。
简单来说,保证一个类在内存中的对象就一个。
RunTime就是典型的单例设计,我们通过对RunTime类的分析,一窥究竟。
2.2 源码剖析
/**
* Every Java application has a single instance of class
* <code>Runtime</code> that allows the application to interface with
* the environment in which the application is running. The current
* runtime can be obtained from the <code>getRuntime</code> method.
* <p>
* An application cannot create its own instance of this class.
*
* @author unascribed
* @see java.lang.Runtime#getRuntime()
* @since JDK1.0
*/
RunTime.java
package java.lang;
public class Runtime {
//1、创建静态的全局唯一的对象
private static Runtime currentRuntime = new Runtime();
//2、私有构造方法,不让外部来调用
/** Don't let anyone else instantiate this class */
private Runtime() {}
//3、通过自定义的静态方法获取实例
public static Runtime getRuntime() {
return currentRuntime;
}
}
2.3 饿汉式
package cn.tedu.design;
//测试单例设计模式--就是按照一定的开发步骤,按照一定的模板进行开发,达到程序中只会有一个实例在干活的目的!!
public class Test5_Design {
public static void main(String[] args) {
//4,测试 new多少次都是一个对象???--
// MySingleTon m = new MySingleTon();--构造方法私有化
MySingleTon m1 = MySingleTon.getMy();
MySingleTon m2 = MySingleTon.getMy();
System.out.println(m1==m2);//是同一个对象吗???
System.out.println(m1.equals(m2));//默认用Object的==
}
}
class MySingleTon {
//1,私有化改造方法 -- 目的就是控制外界创建对象的权利
private MySingleTon() {}
//2,封装创建好的对象 -- 封装,不让外界随意看到我创建的对象
static private MySingleTon my = new MySingleTon();
//3,提供公的获取对象的方法
//静态方法,因为没法new了,还想用,就用类名访问--修饰成静态的
static public MySingleTon getMy(){
return my;//静态只能调静态
}
}
2.4 懒汉式
//懒汉式 -- 面试重点!!延迟加载思想+线程不安全
class MySingleTon2 {
// 1,私有化改造方法 -- 目的就是控制外界创建对象的权利
private MySingleTon2() {
}
// 2,封装创建好的对象 -- 先不创建对象,啥时候用啥时候创建!!
static private MySingleTon2 my;
// 3,提供公的获取对象的方法
// 静态方法,因为没法new了,还想用,就用类名访问--修饰成静态的
synchronized static public MySingleTon2 getMy() {//b,方法里都是同步代码,可以是同步方法
// synchronized (MySingleTon2.class) {//a,同步代码块,静态方法的锁,是类名.class本类的字节码对象
// t1,t2,t3来准备new
if (my == null) {
// t1 new
// t2 new
// t3 new
my = new MySingleTon2();// 开始创建!! 延迟加载
}
// }
return my;// 静态只能调静态
}
}