我是靠谱客的博主 繁荣面包,最近开发中收集的这篇文章主要介绍javaEE多线程(三)---线程安全(二),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

1.volatile(翻译为:易变的,可变性的,无定性的)

2.两种模式:

3.多线程的两种模式

代码实例:(面试考)

4.线程通知(wait(),notify())

5.阻塞队列------BlockingQueue(来自queue的子接口)

6.自己实现的阻塞队列------ArrayBlockingQueue(循环队列)

7.定时器(类)

7.1定时器的使用

7.2自己实现一个定时器(重点)

7.2优化版本的定时器 

8.面试题:sleep和wait的区别

 9.线程池

9.2 为什么使用线程池?

9.3Java中的TreadPoolExecutor的构造方法+创建流程。

9.4线程池

9.5 自己实现一个线程池(这里不太懂)

1.volatile(翻译为:易变的,可变性的,无定性的)

用来修饰变量。保证JVM中线程要读变量,每次从主内存读,保证每次写,写回主内存

功能:(经常改变的变量用volatile修饰)

volatile不可修饰局部变量,没有意义。

a.90%是用来保护内存可见性的(最重要的作用)

b.也可用来保护原子性:long、double修饰的属性(64位)不是原子的,所以要保护它的原子性,要加上volatile。

long a=100;   //不是原子的

double a=100;//不是原子的

volatile long a=100; //原子的

volatile double a=100;//原子的

c.代码的重排序

加上volatile SomeObject so;可以防止代码的重排序。(就不会把她重排序)

手里拿着钥匙(引用)可以去装修房子,拿着毛胚房没用

回顾:判断是否需要保证原子性的两个特点

1.读写操作

a++

size++

2.check update操作

if(...){...}

2.两种模式:

1.单例模式(singleton pattern)

通过代码,保护一个类,使得类在整个进程(应用)运行过程中,有且只有一个对象。

(java中写的图书管理系统)

2.设计模式 

对一些解决通用问题的,经常书写代码片段的总结与归纳(因为多次用到所以写一个方法)

3.多线程的两种模式

饿汉模式:一开始就初始化

懒汉模式:等到用的时候才初始化(Arrays链表、HashMap都是用到来初始化)

代码实例:(面试考)

author wangqi
* @data 2022/2022/4/25/251915
* 懒汉模式3
*/
public class LazyModeV3 {
private volatile static LazyModeV3 instance = null; //避免重排序
public static LazyModeV3 getInstance() {
// 第一次调用这个方法时,说明我们应该实例化对象了
if (instance == null) {
//只有instance 还没有初始化时,才会走到这个分支
//这里没有锁保护,所以理论上可以有很多线程同时走到这个分支
synchronized (LazyModeV3.class) {//如果俩个线程进来了,也只有一个线程会加到锁,然后在判断是否为空
//通过上面的条件,让争抢锁的动作旨在instance
//实例化之前才可能发生,实例化之后就不再发生
//加锁之后才能执行
//第一个抢到锁的线程,看到的instance是null
//其他抢到锁的线程,看到的instance不是null
//保证了instance,只会被实例化一次
if (instance == null) {
instance = new LazyModeV3();
// 只在第一次的时候执行
//上面一行,当重排序成1-3-2时候可能出问题
//通过volatile修复
}
}
}
return instance;
}
private LazyModeV3() {}
}

4.线程通知(wait(),notify())

wait()、notify()方法属于Object类,Java方法都有这俩个方法

要想使用wait和notify,必须对'对象'进行synchronixed加锁

 wait的中止条件有:

1.线程被通知唤醒了

2.线程被中止了(异常)

3.假唤醒(wait醒来的时候条件没有被满足,也被唤醒了)

4.超时时间到达

notify唤醒规则:

1.随机唤醒,notifyAll全部唤醒

2.wait-notify是没有状态保存的,必须先wait后notify

如果先notify后wait,wait无法感知之前曾有过notify,会永远等待下去。

wait(包含重载形式)

notify(包含notifyAll)

wait()之后只会释放wait的这把锁

Object类,所有对象都有。

而Condition(Lock锁)和wait、notify的功能一模一样。

现在更推荐Lock锁相比于synchronized锁

wait、notify天生于sync绑定

5.阻塞队列------BlockingQueue(来自queue的子接口)

阻塞队列:我取不到东西的时候,我就一直等在那里

 put(e) 队列满的情况下放就会阻塞,当有人让线程结束时,放入失败了,也会结束、take();

还有超时的:

6.自己实现的阻塞队列------ArrayBlockingQueue(循环队列)

 一个生产者和一个消费者的问题

生产-消费者模型

生产者:一个(多个线程),只负责向队列放入元素

消费者:一个(多个线程),只负责从队列取出元素

线程和线程之间需要互相等待和通知wait()、notify();

7.定时器(类)

定时器执行任务时,不会占用我们的当前执行流。

Timer类------任务调度作用(闹钟)

abs TimerTask(本身是抽象类)-----继承这个类,重写run方法即可

模式:

多少秒之后执行什么任务。

周期性的执行任务

7.1定时器的使用

 

7.2自己实现一个定时器(重点)

一个延时任务,需要创建一个线程

java中的Timer实现的方式:一个任务,执行多个任务

创建一个工作线程:用优先级阻塞队列,当有很多任务让Timer去执行的时候,把任务放入优先级队列,然后创建一个死循环不断的从优先级队列中去任务执行。

问题:先执行哪个任务?

1.delay时间最小的任务。

其实定时器也是个生产者消费者线程

7.2优化版本的定时器 

多次执行,执行周期性任务

如果有新线程进来,会唤醒所有任务,然后再比较看现在谁应该被执行

 掌握第一个版本即可。

8.面试题:sleep和wait的区别

a.语义不同:休眠VS等待

b.sleep()一定固定休眠时间,wait(timeout)有俩个结束条件:超时时间已到or条件满足。

c.sleep是静态方法

object()普通方法

d.sleep和锁没关系,

wait是释放当前的锁。

 9.线程池

9.2 为什么使用线程池?

因为线程的创建和销毁都需要消耗一定的成本。

线程池模式:

提前创建好很多线程(按需创建)

来了新任务交给储备的线程处理。

处理完了让其重新回到空闲的状态

9.3Java中的TreadPoolExecutor的构造方法+创建流程。

构造方法:

9.4线程池

也是生产者消费者模型

service.execute方法把task任务传入阻塞队列里面 

TreadPoolExecutor(按照按需创建的过程)

1.一开始,线程池里一个工作线程也没有

2.随着任务的提交

//当队列已满时,才会创建新线程

 

构造方法参数:

Executor(接口)

Executors(定义了一些固定策略的线程池) 

问题 

9.5 自己实现一个线程池,我写的是线程不安全的(这里不太懂)

1.首先有一个正式员工和临时员工,都从阻塞队列中读取任务。

代码的结构

正式员工 

 

最后

以上就是繁荣面包为你收集整理的javaEE多线程(三)---线程安全(二)的全部内容,希望文章能够帮你解决javaEE多线程(三)---线程安全(二)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(26)

相关文章

评论列表共有 0 条评论

立即
投稿
返回
顶部