单例模式
单例模式: 保证一个只能存在一个实例
懒汉: 实例等到调用方法时候创建(调用的时候,最后一刻)线程不安全,效率较高
饿汉式: 类第一次加载之后就会创建实例 线程安全,效率较低
静态的内容(静态变量,静态块),在类第一次加载之后就会初始化
实现方式:
1.构造器私有化(外部才不能通过new随便创建对象,对象只能我[类的内部]来创建,给你)
2.私有的,静态的,该类的引用(存储创建了的对象)
3.对外提供一个公共的静态的访问方式(方法)
饿汉式
public class SingleDemo01 {
public static void main(String[] args) {
System.out.println(Single.newInstance());
System.out.println(Single.newInstance());
System.out.println(Single.newInstance());
System.out.println(Single.newInstance());
}
}
//单例 饿汉式
class Single{
//2.私有的静态的Single类型的引用
private static Single single = new Single(); //静态变量会在类第一次加载后初始化,就会创建实例
//1.私有的构造器
private Single() {
// TODO Auto-generated constructor stub
}
//3.公共方法 返回一个当前类型的对象
public static Single newInstance() {
return single;
}
}
懒汉式
public class SingleTonDemo02 {
public static void main(String[] args) {
System.out.println(SingleTon.newInstance());
System.out.println(SingleTon.newInstance());
System.out.println(SingleTon.newInstance());
System.out.println(SingleTon.newInstance().message);
}
}
//懒汉式
class SingleTon{
//2私有的静态的该类的引用
private static SingleTon singleTon;
//1.私有的构造器
private SingleTon(){}
//3.公共的静态的访问方式,返回该类实例
public static SingleTon newInstance() {
//创建对象
//第一次调用方法时候才创建对象,第二次开始就不创建,因为已经有了,直接返回
if(singleTon == null) {
singleTon = new SingleTon();
}
return singleTon;
}
//普通的成员变量
public String message = "这是一个单例模式的类";
//静态变量
//块
//构造器(都得是私有的)
//成员方法
//静态方法
}
进程
执行中的程序叫做进程(Process),是一个动态的概念。
进程是程序的一次动态执行过程, 占用特定的地址空间.
每个进程由3部分组成:cpu,data,code。每个进程都是独立的,保有自己的cpu时间,代码和数据,即便用
同一份程序产生好几个进程,它们之间还是拥有自己的这3样东西。
多任务(Multitasking)操作系统将CPU时间动态地划分给每个进程,操作系统同时执行多个进程,每个进程独
立运行。以进程的观点来看,它会以为自己独占Cpu的使用权
线程
- 线程是进程中一个“单一的连续控制流程” (a single sequential flow of control)/执行路径。线程也可以达到同
一份程序产生好几个进程的效果,但是不同的线程之间可以有某种程度上的资源共享,所以线程又被称为轻
量级进程(lightweight process)。 - Threads run at the same time, independently of one another
- 一个进程可拥有多个并行的(concurrent)线程
- 一个进程中的线程共享相同的内存单元/内存地址空间可以访问相同的变量和对象,而且它们从同一堆中分配
对象通信、数据交换、同步操作 - 由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便而且信息
传递的速度也更快。
创建线程
创建Thread的子类
创建
: 继承 Thread +重写 run
启动
: 创建子类对象 对象.start()
创建 Thread 子类的一个实例并重写 run 方法,run 方法会在调用 start()方法之后被执 行,示例如下:
package day15;
import java.util.stream.DoubleStream;
public class ThreadDemo extends Thread{
@Override
public void run() {
for (int i = 1000; i >=0 ; i--) {
System.out.println("倒计时: "+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread thread = new ThreadDemo();
thread.start();
这种方式的缺点:那就是如果我们的类已经从一个类继承(如小程序必须继承自 Applet 类),则无法再继承Thread 类
通过Runnable接口实现多线程
优点:可以同时实现继承。实现Runnable接口方式要通用一些。
package day15;
import java.util.stream.DoubleStream;
public class ThreadDemo {
public static void main(String[] args) {
ThreadDemo2 th = new ThreadDemo2();
Thread th1 = new Thread(th,"Thread1");
Thread th2 = new Thread(th,"Thread2");
Thread th3 = new Thread(th,"Thread3");
th1.start();
th2.start();
th3.start();
}
}
class ThreadDemo2 implements Runnable{
int tis = 600;
@Override
public void run() {
while (tis > 0){
System.out.println(Thread.currentThread().getName()+"购票 :"+tis--);
}
}
}
线程的五种状态
1)、新生状态: new
2)、就绪状态: runnable
3)、运行状态: running
4)、阻塞状态: blocked
5)、执行完毕: dead
1)、新生状态:选出运动员
2)、就绪状态:走到起跑线,做好跑的动作,枪响后,不是马上就跑,得有反应时间。
3)、运行状态:反应完成后,开始跑
4)、阻塞状态:路边一个石头绊倒了,马上跑起来,嘟囔几句,踢踢石头, 不是马上跑,重新反应进入就绪。
5)、终止状态:跑完了,结束了,慢慢的走几步停下来。
死亡状态是线程生命周期中的最后一个阶段。线程死亡的原因有两个。一个是正常运行的线程完成了它的全部工
作;另一个是线程被强制性地终止,如通过执行stop或destroy方法来终止一个线程
不建议用 stop destory 方法。
线程同步和死锁问题
synchronized同步
由于我们可以通过 private 关键字来保证数据对象只能被方法访问,所以我们只需针对方法提出一套机制,这套
机制就是 synchronized 关键字,
它包括两种用法:synchronized 方法
和 synchronized 块
synchronized 方法:通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。
如:
public synchronized void accessVal(int newVal);
synchronized 方法控制对类成员变量的访问:每个对象对应一把锁,每个 synchronized 方法都必须获得调用该
方法的对象的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此
后被阻塞的线程方能获得 该锁,重新进入可执行状态。
synchronized 方法的缺陷
:若将一个大的方法声明为synchronized 将会大大影响效率,典型地,若将线程类的
方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何
synchronized 方法的调用都永远不会成功。当然我们可以通过将访问类成员变量的代码放到专门的方法中,将其
声明为 synchronized ,并在主方法中调用来解决这一问题,但是 Java 为我们提供了更好的解决办法,那就是
synchronized 块。
synchronized 块:通过 synchronized关键字来声明
用法:
同步块
synchronized(this|类.class| 资源(成员属性)){
要被你同步控制的代码区域-->有可能 会出现问题的代码区域
}
语法如下:
synchronized(syncObject)
{
//允许访问控制的代码
}