Runtime类是一个单例类
每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。通过 getRuntime 方法获取当前运行时对象。代表当前正在运行的程序对象
// 程序运行时对象
Runtime runtime = Runtime.getRuntime();
//可以执行非返回性质的cmd执行代码
//runtime.exec("C://Program Files (x86)/Mozilla Firefox/firefox.exe");//打开任意可执行文件
// runtime.exec("mspaint");// 打开画图
// runtime.exec("calc");// 打开计算器
// runtime.exec("shutdown -s -t 300"); //电脑300秒后自动关机
// runtime.exec("shutdown -a");//取消自动关机
计时器/定时器类,用于定时执行或重复执行某一任务
Timer一种工具,用于在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。
// 计时器对象
// 定时执行或重复执行某一任务
public static void main(String[] args) {
Timer t = new Timer();//创建计时器对象
TimerTask tt=new TimerTask() {
@Override
public void run() {
System.out.println("执行任务");
t.cancel();
}
};
//schedule(TimerTask,long)指定毫秒后执行一次
//t.schedule(tt, 1000);
//schedule(TimerTask,Date)指定时间执行一次
//t.schedule(tt, new Date());
//schedule(TimerTask,start,loop)指定时间后开始执行之后每隔一段时间重复执行
//t.schedule(tt, 1000, 2000);
//schedule(TimerTask,Date,loop)指定时间对象后开始执行之后每隔一段时间重复执行
//t.schedule(tt, new Date(), 1000);
//计时器对象会为每个执行的任务开辟线程进行任务执行,但是不会停止线程
//需要手动调用方法结束计时器,同时结束计时器开辟的相关线程
//t.cancel();//结束计时器
//会结束当前计时器,也会关闭当前计时器对象开辟的所有线程
//所以通常情况下会创建多个计时器对象进行多个任务的执行
线程通信概念:
线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程之间的通信就成为整体的必用方式之一。当线程存在通信指挥,系统间的交互性会更强大,在提高CPU利用率的同时还会对线程任务在处理过程中进行有效的把控与监督。
为了支持多线程之间的协作,JDK提供了两个非常重要的接口线程等待wait()方法和通知notify()方法。这两个方法并不是在Thread类中的,而是输出Object类。这也意味着任何对象都可以调用这2个方法。
1、wait() 和 notify()必须配合synchrozied关键字使用,无论是wait()还是notify()都需要首先获取目标对象的一个监听器。
2、wait()释放锁,而notify()不释放锁。
等待唤醒都是通过锁对象进行的,会将当前执行同步代码块获得锁对象的线程进入等待状态,等待唤醒
新建态(初始态)
使用new创建线程对象时产生的状态
就绪态
调用start方法将线程由新建态转换为就绪态
运行态
系统分配资源给相应准备就绪的线程,自动调用方法后进入运行态
系统会一直监控就绪态的线程,如果有资源会立即分配并执行
阻塞态
调用阻塞或执行阻塞方法,使当前线程进入阻塞态
死亡态
线程运行结束后进入死亡态
start方法与run方法的区别(为什么重写的时run方法调用start方法开启线程)
1、状态转换的区别
start方法将线程由新建态转换为就绪态,run方法是就绪态转换为运行态,
2、调用方的区别
start由调用方调用执行。Run方法由系统自动调用,线程运行需要系统提供资源。
run方法可不可以直接调用?
可以,但是如果直接调用就相当于普通方法,没有系统分配资源开辟线程,而是在主线程中直接运行。 与多线程无关,相当于定义了一个run方法并创建对象调用。
一个线程要想运行需要满足两个条件。1.获取运行资源(开辟线程)2.获取锁
yeid方法,线程礼让方法,不会释放锁,但是会让出资源,如果资源充足的情况下,调不调用没有影响
将线程由运行态转换为就绪态
wait方法,线程等待方法,将资源与锁全部让去进入类似与休眠的状态,等待唤醒
将线程由运行态转换为阻塞态
sleep方法,线程休眠方法,资源与锁都不会释放,将线程由运行态转换为阻塞态,当休眠时间到达,自动由阻塞态转换为就绪态
notify/notifyAll方法,线程唤醒方法,通常与wait方法一起使用,用于唤醒等待的线程,使其由阻塞态进入就绪态
对于避免不可见性问题,Java还提供了一种弱形式的同步,即使用了volatile关键字。该关键字确保了对一个变量的更新对其他线程可见。当一个变量被声明为volatile时候,线程写入时候不会把值缓存在寄存器或者或者在其他地方,当线程读取的时候会从主内存重新获取最新值,而不是使用当前线程的拷贝内存变量值。volatile虽然提供了可见性保证,但是不能使用他来构建复合的原子性操作,也就是说当一个变量依赖其他变量或者更新变量值时候新值依赖当前老值时候不在适用。
多个线程对同一变量进行操作时,可能由于同时运行导致数据输出的错误。
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
设计模式就是完成某一问题的最佳解决方案,由前人总结梳理可以直接使用的方案。
软件开发中设计模式23种
一个应用程序中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一般通过getInstance()的方法来获取它们的实例。getInstance()的返回值是一个对象的引用,并不是一个新的实例,所以不要错误的理解成多个对象。
懒汉单例模式
在第一次使用时创建指定对象
饿汉单例模式
在声明类是创建指定对象
饿汉模式会在声明类时创建对象占用内存资源。
双重校验锁单例模式(双重校验锁懒汉模式)
使用双重校验保证线程的安全性
对已有的业务逻辑进一步的封装,使其增加额外的功能,如Java中的IO流就使用了装饰者模式,用户在使用的时候,可以任意组装,达到自己想要的效果。 举个栗子,我想吃三明治,首先我需要一根大大的香肠,我喜欢吃奶油,在香肠上面加一点奶油,再放一点蔬菜,最后再用两片面包夹一下,很丰盛的一顿午饭,营养又健康。
练习
1、使用runtime与timer类实现,每隔2秒执行关机指令,每个1秒执行取消关机指令,关机指令延时1秒执行,取消指令延时2秒执行,当程序执行1分钟后结束任务
2、使用runtime与timer类实现,每隔1秒开启计算器,每隔2秒开启画图,当程序执行1分钟后结束计算器任务,当执行2分钟后结束画图任务
3、使用runtime类实现,代码执行后在晚上9点将计算机关闭(不论什么时候执行,例:在早9点执行显示12小时候关闭,若在晚9点后执行则立即关闭)
4、使用wait与notfit实现两个线程交替运行
5、使用装饰者模式完成护甲的添加
6、使用观察者模式完成Up更新通知粉丝的效果
Up主为被观察者 保存所有粉丝集合
粉丝为观察者 拥有接受up主消息的方法
粉丝对象额外拥有关注up主方法 与取关up主方法
Up有拉黑粉丝方法