导图社区 架构师
架构师学习内容:并发编程、网络编程、JVM核心、分布式框架、搜索、负载均衡、linux基础、中间件、DB、流式计算、文件系统
编辑于2020-12-12 10:45:48程序猿知识技能总结大全,java、python、正则表达式、Linux等多方面知识导图
包含抖音运营、短视频运营要点、运营之光、从零开始做运营、学会写作等多个运营读书笔记、运营知识框架等
产品、运营工具包大全:办公工具、文字工具、音频工具、视频工具、社群工具、公众号辅助工具、排版工具、图片工具、H5工具、小程序工具等
项目管理流程竖版思维导图、从需求收集、需求评审、规划阶段、再到方案实现阶段、测试阶段、至最后的上线阶段,详细描述每个阶段的工作内容
产品需求文档(PRD)是确保团队理解项目需求和目标的关键文档。在撰写PRD时,要明确项目背景、需求类型,遵循有理有据、全面清晰、易读的写作原则。选择适当的工具如Axure或Word,包括文档修改记录、项目背景、名词解释、流程图、需求说明等内容。使用原型工具结合需求,提供清晰的视觉参考。详细描述每个功能点,包括权限、规则逻辑、极值、交互等。使用标点符号、示例、标记重要内容,提高文档可读性。最终,根据项目需求决定是否包含额外的内容,以确保PRD有效指导项目开发。
系统集成项目管理工程师-十大管理输入、输出、工具总结,软考必备复习导图
社区模板帮助中心,点此进入>>
程序猿知识技能总结大全,java、python、正则表达式、Linux等多方面知识导图
包含抖音运营、短视频运营要点、运营之光、从零开始做运营、学会写作等多个运营读书笔记、运营知识框架等
产品、运营工具包大全:办公工具、文字工具、音频工具、视频工具、社群工具、公众号辅助工具、排版工具、图片工具、H5工具、小程序工具等
项目管理流程竖版思维导图、从需求收集、需求评审、规划阶段、再到方案实现阶段、测试阶段、至最后的上线阶段,详细描述每个阶段的工作内容
产品需求文档(PRD)是确保团队理解项目需求和目标的关键文档。在撰写PRD时,要明确项目背景、需求类型,遵循有理有据、全面清晰、易读的写作原则。选择适当的工具如Axure或Word,包括文档修改记录、项目背景、名词解释、流程图、需求说明等内容。使用原型工具结合需求,提供清晰的视觉参考。详细描述每个功能点,包括权限、规则逻辑、极值、交互等。使用标点符号、示例、标记重要内容,提高文档可读性。最终,根据项目需求决定是否包含额外的内容,以确保PRD有效指导项目开发。
系统集成项目管理工程师-十大管理输入、输出、工具总结,软考必备复习导图
架构师
并发编程
基础
线程安全
当多个线程访问某一个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的
synchronized
可以在任何对象及方法上加锁,而加锁的这段代码称为“互斥区”或“临界区”。
示例
```java public class MyThread extends Thread{ private int count = 5 ; //synchronized加锁 public void run(){ count--; System.out.println(this.currentThread().getName() + " count = "+ count); } public static void main(String[] args) { /** * 分析:当多个线程访问myThread的run方法时,以排队的方式进行处理(这里排对是按照CPU分配的先后顺序而定的), * 一个线程想要执行synchronized修饰的方法里的代码: * 1 尝试获得锁 * 2 如果拿到锁,执行synchronized代码体内容;拿不到锁,这个线程就会不断的尝试获得这把锁,直到拿到为止, * 而且是多个线程同时去竞争这把锁。(也就是会有锁竞争的问题) */ MyThread myThread = new MyThread(); Thread t1 = new Thread(myThread,"t1"); Thread t2 = new Thread(myThread,"t2"); Thread t3 = new Thread(myThread,"t3"); Thread t4 = new Thread(myThread,"t4"); Thread t5 = new Thread(myThread,"t5"); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } } ```
多个线程多个锁
多个线程,每个线程都可以拿到自已指定的锁,分别获得锁之后,执行synchronized方法体的内容。
示例
```java /** * 关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当做锁, * 所以代码中哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock), * * 在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class类)。 * */ public class MultiThread { private int num = 0; /** static */ public synchronized void printNum(String tag){ try { if(tag.equals("a")){ num = 100; System.out.println("tag a, set num over!"); Thread.sleep(1000); } else { num = 200; System.out.println("tag b, set num over!"); } System.out.println("tag " + tag + ", num = " + num); } catch (InterruptedException e) { e.printStackTrace(); } } //注意观察run方法输出顺序 public static void main(String[] args) { //俩个不同的对象 final MultiThread m1 = new MultiThread(); final MultiThread m2 = new MultiThread(); Thread t1 = new Thread(new Runnable() { @Override public void run() { m1.printNum("a"); } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { m2.printNum("b"); } }); t1.start(); t2.start(); } } ```
对象锁的同步和异步
同步(synchronized)
同步的概念就是共享,牢牢记住“共享”这两个字,如果不是共享的资源,就没有必要进行同步 同步的目的是为了线程安全,需要满足两个特性: - 原子性(同步) - 可见性
异步(asynchronized)
异步的概念就是独立,相互之间不受到任何制约。比如学习http的时候,页面发起ajax请求,我们还可以继续或者操作页面的内容,二者之间没有任何关系
示例
```java /** * 对象锁的同步和异步问题 * */ public class MyObject { public synchronized void method1(){ try { System.out.println(Thread.currentThread().getName()); Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } } /** synchronized */ public void method2(){ System.out.println(Thread.currentThread().getName()); } public static void main(String[] args) { final MyObject mo = new MyObject(); /** * 分析: * t1线程先持有object对象的Lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法 * t1线程先持有object对象的Lock锁,t2线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步 */ Thread t1 = new Thread(new Runnable() { @Override public void run() { mo.method1(); } },"t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { mo.method2(); } },"t2"); t1.start(); t2.start(); } } ```
脏读
在我们对一个对象的方法加锁的时候,需要考虑业务的完整性,即为setValue/getValue方法同时加锁synchronized同步关键字,保证业务(service)的原子性,不然会出现业务错误(也从侧面保证业务的一致性)
示例
```java /** * 业务整体需要使用完整的synchronized,保持业务的原子性。 */ public class DirtyRead { private String username = "bjsxt"; private String password = "123"; public synchronized void setValue(String username, String password){ this.username = username; try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } this.password = password; System.out.println("setValue最终结果:username = " + username + " , password = " + password); } public void getValue(){ System.out.println("getValue方法得到:username = " + this.username + " , password = " + this.password); } public static void main(String[] args) throws Exception{ final DirtyRead dr = new DirtyRead(); Thread t1 = new Thread(new Runnable() { @Override public void run() { dr.setValue("z3", "456"); } }); t1.start(); Thread.sleep(1000); dr.getValue(); } } ```
synchronized细节问题
锁重入
关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到了一个对象的锁后,再次请求此对象时是可以再次得到该对象的锁
示例
```java /** * synchronized的重入 */ public class SyncDubbo1 { public synchronized void method1(){ System.out.println("method1.."); method2(); } public synchronized void method2(){ System.out.println("method2.."); method3(); } public synchronized void method3(){ System.out.println("method3.."); } public static void main(String[] args) { final SyncDubbo1 sd = new SyncDubbo1(); Thread t1 = new Thread(new Runnable() { @Override public void run() { sd.method1(); } }); t1.start(); } } ```
父子类锁重入示例
```java /** * synchronized的重入 */ public class SyncDubbo2 { static class Main { public int i = 10; public synchronized void operationSup(){ try { i--; System.out.println("Main print i = " + i); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } static class Sub extends Main { public synchronized void operationSub(){ try { while(i > 0) { i--; System.out.println("Sub print i = " + i); Thread.sleep(100); this.operationSup(); } } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Thread t1 = new Thread(new Runnable() { @Override public void run() { Sub sub = new Sub(); sub.operationSub(); } }); t1.start(); } } ```
锁异常的处理示例
```java /** * synchronized异常 */ public class SyncException { private int i = 0; public synchronized void operation(){ while(true){ try { i++; Thread.sleep(100); System.out.println(Thread.currentThread().getName() + " , i = " + i); if(i == 20){ //Integer.parseInt("a"); throw new RuntimeException(); } } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { final SyncException se = new SyncException(); Thread t1 = new Thread(new Runnable() { @Override public void run() { se.operation(); } },"t1"); t1.start(); } } ```
其他示例
减少锁的粒度
使用synchronized声明的方法在某些情况下是有弊端的,比如A线程调用同步的方法执行一个很长时间的任务,那么B线程就必须等待比较长的时间才能执行,这样的情况下可以使用synchronized代码块去优化代码执行时间 ```java /** * 使用synchronized代码块减小锁的粒度,提高性能 */ public class Optimize { public void doLongTimeTask(){ try { System.out.println("当前线程开始:" + Thread.currentThread().getName() + ", 正在执行一个较长时间的业务操作,其内容不需要同步"); Thread.sleep(2000); synchronized(this){ System.out.println("当前线程:" + Thread.currentThread().getName() + ", 执行同步代码块,对其同步变量进行操作"); Thread.sleep(1000); } System.out.println("当前线程结束:" + Thread.currentThread().getName() + ", 执行完毕"); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { final Optimize otz = new Optimize(); Thread t1 = new Thread(new Runnable() { @Override public void run() { otz.doLongTimeTask(); } },"t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { otz.doLongTimeTask(); } },"t2"); t1.start(); t2.start(); } } ```
使用Object进行加锁,比较灵活
```java /** * 使用synchronized代码块加锁,比较灵活 */ public class ObjectLock { public void method1(){ synchronized (this) { //对象锁 try { System.out.println("do method1.."); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } public void method2(){ //类锁 synchronized (ObjectLock.class) { try { System.out.println("do method2.."); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } private Object lock = new Object(); public void method3(){ //任何对象锁 synchronized (lock) { try { System.out.println("do method3.."); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { final ObjectLock objLock = new ObjectLock(); Thread t1 = new Thread(new Runnable() { @Override public void run() { objLock.method1(); } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { objLock.method2(); } }); Thread t3 = new Thread(new Runnable() { @Override public void run() { objLock.method3(); } }); t1.start(); t2.start(); t3.start(); } } ```
不要使用String常量加锁,会出现死循环问题
```java /** * synchronized代码块对字符串的锁,注意String常量池的缓存功能 */ public class StringLock { public void method() { //new String("字符串常量") synchronized ("字符串常量") { try { while(true){ System.out.println("当前线程 : " + Thread.currentThread().getName() + "开始"); Thread.sleep(1000); System.out.println("当前线程 : " + Thread.currentThread().getName() + "结束"); } } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { final StringLock stringLock = new StringLock(); Thread t1 = new Thread(new Runnable() { @Override public void run() { stringLock.method(); } },"t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { stringLock.method(); } },"t2"); t1.start(); t2.start(); } } ```
锁对象改变问题
当使用一个对象进行加锁的时候,要注意对象本身发生改变的时候,那么持有的锁就不同。如果对象本身不发生改变,那么依然是同步的,即使是对象的属性发生了改变。 ```java /** * 锁对象的改变问题 */ public class ChangeLock { private String lock = "lock"; private void method(){ synchronized (lock) { try { System.out.println("当前线程 : " + Thread.currentThread().getName() + "开始"); lock = "change lock"; Thread.sleep(2000); System.out.println("当前线程 : " + Thread.currentThread().getName() + "结束"); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { final ChangeLock changeLock = new ChangeLock(); Thread t1 = new Thread(new Runnable() { @Override public void run() { changeLock.method(); } },"t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { changeLock.method(); } },"t2"); t1.start(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } t2.start(); } } ``` ```java /** * 同一对象属性的修改不会影响锁的情况 */ public class ModifyLock { private String name ; private int age ; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public synchronized void changeAttributte(String name, int age) { try { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 开始"); this.setName(name); this.setAge(age); System.out.println("当前线程 : " + Thread.currentThread().getName() + " 修改对象内容为: " + this.getName() + ", " + this.getAge()); Thread.sleep(2000); System.out.println("当前线程 : " + Thread.currentThread().getName() + " 结束"); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { final ModifyLock modifyLock = new ModifyLock(); Thread t1 = new Thread(new Runnable() { @Override public void run() { modifyLock.changeAttributte("张三", 20); } },"t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { modifyLock.changeAttributte("李四", 21); } },"t2"); t1.start(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } t2.start(); } } ```
死锁问题
```java /** * 死锁问题,在设计程序时就应该避免双方相互持有对方的锁的情况 */ public class DeadLock implements Runnable{ private String tag; private static Object lock1 = new Object(); private static Object lock2 = new Object(); public void setTag(String tag){ this.tag = tag; } @Override public void run() { if(tag.equals("a")){ synchronized (lock1) { try { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock1执行"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock2) { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock2执行"); } } } if(tag.equals("b")){ synchronized (lock2) { try { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock2执行"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock1) { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock1执行"); } } } } public static void main(String[] args) { DeadLock d1 = new DeadLock(); d1.setTag("a"); DeadLock d2 = new DeadLock(); d2.setTag("b"); Thread t1 = new Thread(d1, "t1"); Thread t2 = new Thread(d2, "t2"); t1.start(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } t2.start(); } } ```
volatile关键字
使变量在多个线程间可见 ```java public class RunThread extends Thread{ private volatile boolean isRunning = true; private void setRunning(boolean isRunning){ this.isRunning = isRunning; } public void run(){ System.out.println("进入run方法.."); int i = 0; while(isRunning == true){ //.. } System.out.println("线程停止"); } public static void main(String[] args) throws InterruptedException { RunThread rt = new RunThread(); rt.start(); Thread.sleep(1000); rt.setRunning(false); System.out.println("isRunning的值已经被设置了false"); } } ``` 在Java中,每一个线程都会有一块工作内存区,其中存放着所有线程共享的主内存中的变量值的拷贝。当线程执行时,他在自已工作内存区中操作这些变量。为了存取一个共享的变量,一个线程通常先获取锁定并去清除它的内存工作区,把这些共享变量从所有线程的共享内存区中正确的装入到他自已所在的工作内存区中,当线程解锁时保证该工作内存区中变量的值写回到共享内存中。 一个线程可以执行的操作有使用(use)、赋值(assign)、装载(load)、存储(store)、锁定(lock)、解锁(unlock). 而主内存可以执行的操作有读(read)、写(write)、锁定(lock)、解锁(unlock),每个操作都是原子的。 volatile关键字的作用就是强制线程到主内存(共享内存)里去读取变量,而不去线程工作内存区里去读取,从而实现了多个线程间的变量可见。也就是满足线程安全的可见性。
非原子性
volatile关键字虽然拥有多线程之间的可见性,但是却不具备同步性(也就是原子),可以算上是一个轻量的synchronized,性能要比synchronized强很多,不会造成阻塞。 一般volatile用于只针对于多个线程可见的变量操作,并不能代替synchronized的同步功能 ```java /** * volatile关键字不具备synchronized关键字的原子性(同步) */ public class VolatileNoAtomic extends Thread{ //private static volatile int count; private static AtomicInteger count = new AtomicInteger(0); private static void addCount(){ for (int i = 0; i < 1000; i++) { //count++ ; count.incrementAndGet(); } System.out.println(count); } public void run(){ addCount(); } public static void main(String[] args) { VolatileNoAtomic[] arr = new VolatileNoAtomic[100]; for (int i = 0; i < 10; i++) { arr[i] = new VolatileNoAtomic(); } for (int i = 0; i < 10; i++) { arr[i].start(); } } ```
建议使用atomic类的系列对象
```java import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; public class AtomicUse { private static AtomicInteger count = new AtomicInteger(0); //多个addAndGet在一个方法内是非原子性的,需要加synchronized进行修饰,保证4个addAndGet整体原子性 /**synchronized*/ public synchronized int multiAdd(){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } count.addAndGet(1); count.addAndGet(2); count.addAndGet(3); count.addAndGet(4); //+10 return count.get(); } public static void main(String[] args) { final AtomicUse au = new AtomicUse(); List<Thread> ts = new ArrayList<Thread>(); for (int i = 0; i < 100; i++) { ts.add(new Thread(new Runnable() { @Override public void run() { System.out.println(au.multiAdd()); } })); } for(Thread t : ts){ t.start(); } } } ```
多线程通信(wait和notify)
queue模拟
单例和多线程
Queue讲解
同步类容器和并发类容器
Concurrent与CopyOnWrite容器
设计模式
future模式讲解
MasterWorker模式讲解
深入
锁的高级(线程池)
重入锁、读写锁,锁的高级深化
Disruptor并发框架
网络编程
SocketIO网络编程基础篇
Netty课程入门网络编程中级篇
Netty课程深入网络编程高级篇
Netty实现文件上传下载网络编程高级篇
JVM核心
jvm虚拟机组成部分讲解、jvm虚拟机参数使用讲解并发编程框架篇
jvm垃圾收集算法讲解、及对象的分代转换并发编程框架篇
分布式框架
dubbo
Dubbo分布式服务治理简介、入门示例讲解、管控台部署使用
Dubbo依赖检查讲解、负载均衡配置、集群容错配置
Dubbox 入门讲解、Kryo序列化框架、容器讲解
搜索
Solr环境搭建、IK中文分词器安装与使用
Solrjavabean与solr注解使用、SSI框架整合Solr使用讲解、管理员命令使用讲解
负载均衡
Nginx入门简介、虚拟主机配置、日志分析
Nginx后续
Linux基础
常用命令讲解
深入进程管理、shell编程、计划任务
Shell编程入门、基础知识、编程语句
中间件
redis
Nosql、Redis入门课程讲解,安装、部署、命令
Redis基础数据类型详解
Redis高级命令、主从复制、安全性、哨兵
Redis事物、持久化机制、发布与订阅模式
Redis集群搭建
Redis集群操作与spring整合
mq
ActiveMQ
ActiveMQ初步、详细使用
ActiveMQ与spring整合,集群监控,配置优化
Zookeeper+ActiveMQ集群:网络连接模式(network connector)详解
RocketMQ
RocketMQ简介、环境搭建
RocketMQ HelloWorld示例、 重试策略讲解
RocketMQ 架构设计、双主双从集群环境搭建、顺序消费、事务消费
RocketMQ API使用简介、拉取机制
RocketMQ实战案例讲解
RocketMQ事物讲解
Kafka
KafKa安装与使用、KafKaSpout使用
注册中心
Zookeeper简介、集群环境搭建
Zookeeper 配置文件讲解、客户端使用
Zookeeper Watcher核心机制讲解、安全认证讲解、实际应用讲解
ZKClientAPI讲解、CuratorAPI讲解、框架、分布式锁讲解、实现多个Watcher集群操作
DB
Oracle
Oracle基础回顾、高级使用、分析函数
Oracle事物和锁,用户操作、索引和索引碎片问题解决
Oracle用户操作、赋权、事务、锁、索引资料
Oracle之同义词,DBLINK,表空间、垂直水平分库分表
Oracle之表分区、分区索引、数据分析及解决方案
流式计算
Storm分布式流式计算简介、环境搭建、集群环境提交Topology、Spout、Bolt、Topology概念
StormWorker、Executor、Task配置详解、分组模式讲解
Storm WorldCount例子、保证机制、Drpc讲解
Trident学习使用、结合Redis使用、Solr
文件系统
FastDFS
FastDFS简介、环境搭建与使用
FastDFS集群环境搭建+Nginx缓存、负载均衡等整合
Web项目与fastdfs集群进行整合,实现文件的上传下载等功能
Web项目实现对fastdfs文件进行定时任务清理工作