java第二十四天之学到辽~
线程池
定时器
设计模式
1.1 线程间的等待唤醒机制
Object 类中
void wait () 在其他线程调用此对象的 notify () 方法或 notifyAll () 方法前,导致当前线程等待。
void wait (long timeout) 在其他线程调用此对象的 notify () 方法或 notifyAll () 方法,或者超过指定的时间量前,导致当前线程等待。
void notify () 唤醒在此对象监视器上等待的单个线程。
void notifyAll () 唤醒在此对象监视器上等待的所有线程。
1.2 多线程(内存可见性问题 volatile)
* volatile 解决内存可见性问题
(1) Java内存模型
Java内存模型规定了所有的变量都存储在主内存中。每条线程中还有自己的工作内存,
线程的工作内存中保存了被该线程所使用到的变量(这些变量是从主内存中拷贝而来)。
线程对变量的所有操作(读取,赋值)都必须在工作内存中进行。
不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。
(2) Java中的可见性
* Java提供了volatile关键字来保证可见性。
* 当一个共享变量被volatile修饰时,会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。
* 而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的。
* 通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,
并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。
volatile 关键字:当多个线程进行操作共享数据时,可以保证内存中的数据可见。
相较于 synchronized 是一种较为轻量级的同步策略。
* volatile 变量,用来确保将变量的更新操作通知到其他线程。
可以将 volatile 看做一个轻量级的锁,
但是又与锁有些不同:
对于多线程,不是一种互斥关系
能保证变量状态的“原子性操作”
例子:
public class MyTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
while (true){
if (myRunnable.getFlag()) {
System.out.println("进来了");
break;
}
}
}
//要说内存可见性问题,得先了解一下我们JVM的内存模型
//Java内存模型规定了所有的变量都存储在主内存中。每条线程中还有自己的工作内存,
//线程的工作内存中保存了被该线程所使用到的变量(这些变量是从主内存中拷贝而来)。
//线程对变量的所有操作(读取,赋值)都必须在工作内存中进行。
//不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。
//volatile 只是解决内存可见性的问题,但是他不能保证原子性,原子性:就是不可再分割性
}
class MyRunnable implements Runnable{
volatile boolean flag=false;
public boolean getFlag() {
return flag;
}
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag=true;
System.out.println("flag的值是"+getFlag());
}
}
1.3 多线程(CAS 算法)
* CAS 算法
(1)CAS (Compare-And-Swap) 是一种硬件对并发的支持,针对多处理器操作而设计的处理器中的
一种特殊指令,用于管理对共享数据的并发访问
(2) CAS 是一种无锁的非阻塞算法的实现。
* CAS 包含了 3 个操作数:
(1) 需要读写的内存值 V
(2) 进行比较的值 A
(3) 拟写入的新值 B
当且仅当 V 的值等于 A 时, CAS 通过原子方式用新值 B 来更新 V 的值,否则不会执行任何操作
jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronouse同步锁的一种乐观锁。JDK 5之前Java语言是靠synchronized关键字保证同步的,这是一种独占锁,也是是悲观锁。
* java.util.concurrent.atomic 包下提供了一些原子操作的常用类:
AtomicBoolean 、 AtomicInteger 、 AtomicLong 、 AtomicReference
AtomicIntegerArray 、 AtomicLongArray
AtomicMarkableReference
AtomicReferenceArray
例子:
public class MyTest2 {
public static void main(String[] args) {
//i++ 不是一个原子性操作
//CAS 算法:比较并交换
//是一种硬件支持
IRunnable iRunnable = new IRunnable();
for (int i = 0; i < 10; i++) {
new Thread(iRunnable).start();
}
}
}
class IRunnable implements Runnable{
// int i=0;
//把普通变量换成原子变量,
AtomicInteger num=new AtomicInteger(1);
@Override
public void run() {
while (true){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + num.getAndIncrement());
}
}
}
1.4 多线程(线程的状态转换图及常见执行情况)
新建 , 就绪 , 运行 , 冻结 , 死亡
新建:线程被创建出来
就绪:具有CPU的执行资格,但是不具有CPU的执行权
运行:具有CPU的执行资格,也具有CPU的执行权
阻塞:不具有CPU的执行资格,也不具有CPU的执行权
死亡:不具有CPU的执行资格,也不具有CPU的执行权
1.5 多线程(线程池的概述和使用)
* 线程池概述
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。
而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。
线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池
* 内置线程池的使用概述
JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
public static ExecutorService newCachedThreadPool(): 根据任务的数量来创建线程对应的线程个数
public static ExecutorService newFixedThreadPool(int nThreads): 固定初始化几个线程
public static ExecutorService newSingleThreadExecutor(): 初始化一个线程的线程池
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
Future> submit(Runnable task)
Future submit(Callable task)
使用步骤:
创建线程池对象
创建Runnable实例
提交Runnable实例
关闭线程池
例子:
public class MyTest2 {
public static void main(String[] args) {
//线程池:是一个容器,装有一定线程对象的容器
//为什么要线程池
//从JDK5开始,Java内置支持线程池
//B:
//内置线程池的使用概述
//JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
//ExecutorService 线程池
// public static ExecutorService newCachedThreadPool ():根据任务的数量来创建线程对应的线程个数
ExecutorService executorService = Executors.newCachedThreadPool();
MyRunnable myRunnable = new MyRunnable();
executorService.submit(myRunnable);
executorService.submit(new MyRunnable());
executorService.submit(new MyRunnable());
executorService.submit(new MyRunnable());
executorService.submit(new MyRunnable());
executorService.submit(new MyRunnable());
executorService.submit(new MyRunnable());
//关闭线程池
executorService.shutdown();
}
}
public class MyTest3 {
public static void main(String[] args) {
//这个线程里面,提前创建三个线程对象
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(new MyRunnable());
executorService.submit(new MyRunnable());
executorService.submit(new MyRunnable());
executorService.submit(new MyRunnable());
executorService.submit(new MyRunnable());
executorService.submit(new MyRunnable());
executorService.shutdown();
}
}
1.7 多线程(定时器的概述和使用)
* 定时器概述
定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。
在Java中,可以通过Timer和TimerTask类来实现定义调度的功能。
* Timer和TimerTask
Timer:
public Timer()
public void schedule(TimerTask task, long delay):
public void schedule(TimerTask task,long delay,long period);
public void schedule(TimerTask task, Date time):
public void schedule(TimerTask task, Date firstTime, long period):
TimerTask:定时任务
public abstract void run()
public boolean cancel()
开发中
Quartz是一个完全由java编写的开源调度框架。
例子:
public class MyTest3 {
public static void main(String[] args) throws ParseException {
//定时删除文件夹
Timer timer = new Timer();
String dateStr = "2019-07-30 14:42:00";
Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr);
MyTimerTask myTimerTask = new MyTimerTask(timer);
timer.schedule(myTimerTask,date);
}
}
public class MyTimerTask extends TimerTask {
Timer timer;
public MyTimerTask(Timer timer) {
this.timer=timer;
}
@Override
public void run() {
File file = new File("E:\\测试图片");
delFolder(file);
timer.cancel();//取消定时器
}
private void delFolder(File file) {
File[] files = file.listFiles();
for (File f : files) {
if(f.isFile()){
f.delete();
}else{
delFolder(f);
}
}
file.delete();
}
}
1.8 设计模式(设计模式的概述和分类)
* 设计模式概述
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编写、代码设计经验的总结。
使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性以及代码的结构更加清晰.
* 设计模式分类
创建型模式(创建对象的): 单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。
行为型模式(对象的功能): 适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
结构型模式(对象的组成): 模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。
1.9 设计模式(简单工厂模式概述和使用)
* 简单工厂模式概述: 又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例
* 优点: 使用静态工厂模式的优点是实现责任的分割,该模式的核心是工厂类,工厂类含有必要的选择逻辑,可以决定什么时候创建哪一个产品的实例,
而客户端则免去直接创建产品的责任,而仅仅是消费产品。也就是说静态工厂模式在不改变客户端代码的情况可以动态的增加产品。
明确了类的职责
* 缺点
这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,
就需要不断的修改工厂类,不利于后期的维护
2.1 设计模式(工厂方法模式的概述和使用)
* 工厂方法模式概述
工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。
* 优点
客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,
只需要增加一个具体的类和具体的工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性
* 缺点: 需要额外的编写代码,增加了工作量
2.2 设计模式(单例模式之懒汉式)
* 饿汉式和懒汉式的区别
单例设计模式之懒汉式
开发中 饿汉式
面试中 懒汉式
a: 线程安全思想
b: 延迟加载思想
2.3 设计模式(单例模式的Java代码体现Runtime类)
A:Runtime类概述
每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时。
应用程序不能创建自己的 Runtime 类实例。