IDEA的LeetCode力扣插件设置与使用
IDEA整合LeetCode的插件,有了这个插件,可以在IDEA本地编辑代码并且运行提交,还能关联自己的账号,简直实用之极。看网上介绍的都不太详细,我来写个清楚点的。插件如图:
一:下载插件
点击intelij Idea->Preferences->Plugins:
搜索leetcode下载就行了。如果你的搜不到,可以尝试重新打开Setting重新搜,还没有的话,可以去官网插件库下载,然后导入就可以了。链接:https://plugins.jetbrains.com/plugin/12132-leetcode-editor
二:配置
安装完成之后,点击IdealiJ idea->Preference->Tools->leetcode plugin,
也可以点击右下角的leetcode图标
配置界面如图:
注意:上图中TempFilePath对应的文件夹一定要是你此项目模块源码的位置 。我的新建一个项目的意思是,像我那样重新建一个名为“LeetCode”的项目,然后选择其src目录,评论区红色无效文件可能就是这个原因。
关于下面几个参数的定义,官方给的是:
Custom code template: 开启使用自定义模板,否则使用默认生成格式
CodeFileName: 生成文件的名称,默认为题目标题
CodeTemplate: 生成题目代码的内容,默认为题目描述和题目代码
TemplateConstant: 模板常用变量
${question.title}:题目标题,例如:两数之和
${question.titleSlug}:题目标记,例如:two-sum
${question.frontendQuestionId}:题目编号,例如:1
${question.content}:题目描述内容
${question.code}:题目代码部分
$!velocityTool.camelCaseName(str):一个函数,用来将字符串转化为驼峰样式
CodeFileName这个里面填的就是以后自动生成类的类名,使用我的这个配置刚好可以
1 | P$!{question.frontendQuestionId}$!velocityTool.camelCaseName(${question.titleSlug}) |
CodeTemplate就是自动生成的代码格式,对于有强迫症的人来说,这个自动生成的格式就非常重要了,不然看着心里就烦。其中main()方法是用来debug的。我的配置(如果复制过去格式不对,请手动改成我这样的,空行也不要删):
1 | package leetcode.editor.cn; |
就这样自动生成的代码是这样的,个人觉得还可以:
注意:
在生成的自定义代码中包含两行关键信息:
leetcode submit region begin(Prohibit modification and deletion):提交到leetcode进行验证的代码开始标记
leetcode submit region end(Prohibit modification and deletion):提交到leetcode进行验证的代码结束标记
这两行标记标示了提交到leetcode服务器进行验证的代码范围,在此范围内只允许有出现与题目解答相关的内容,出现其他内容可能导致leetcode验证不通过。
除了此范围内,其他区域是可以任意填写的,内容不会提交到leetcode,可以增加一些可以本地调试的内容,例如:import java.util.Arrays;
所以,这两行内容是不能被删除和修改的,否则将识别不到提交的内容。
补充:
如图中的文档注释中的类,没有快捷键可以一次性取消,如果一行一行删又太费事 ,我们可以用这个方法。
光标放在这里,按下Alt+鼠标左键,就可以对多行进行删除,简单方便。
三:使用
点击左下角的按钮,然后点击上面的小地球进行联网登录,登陆成功就是图中的画面了。双击题目,就会自动创建类
写完代码,右键
如图,就可以运行测试和提交了,在下面的Event Log可以查看运行情况
spark源码阅读-spark启动流程 1 spark-submit shell端运行流程
spark 的启动流程?
shell端的启动流程
以一个常规的wordcount 程序spark启动命令为例,spark在shell端的启动流程如下
- 首先,用户在shell端提交spark提交命令,一个常见的workcount提交命令如下
1 | ./spark-submit --master yarn-client \ |
该命令表示像yarn提交一个spark程序进行运行,在shell端的执行流程如下。
- spark-submit 比较简单,直接将shell后面的参数转交给spark-class,并告诉spark-class以后运行的java类为 org.apache.spark.deploy.SparkSubmit。
1 | exec "${SPARK_HOME}"/bin/spark-class org.apache.spark.deploy.SparkSubmit "$@" |
- 此时程序在spark-class执行
- spark-class会对环境变量做一些简单的查找和配置,如设置SPARK_HOME,SPARK_JARS_DIR,JAVA_HOME等
- 调用build_command方法获取最终要执行的java命令,该命令会调用org.apache.spark.launcher.Main
build_command的代码如下
1 | build_command() { |
该代码将shell后面的参数传入org.apache.spark.launcher.Main,获取执行结果
- org.apache.spark.launcher.Main,该类根据传入的参数,拼装classpath,jar等参数,返回最终要执行的java命令给spark-class
- 输入:shell后面自带的参数,如
–class com.example.spark.WordCount
–executor-memory 1G - 输出我们看到的最终执行的java命令,如
1
2
3
4/opt/java/bin/java -cp /opt/spark/conf/:/opt/spark/jars/* \
-Xmx1g org.apache.spark.deploy.SparkSubmit --master yarn \
--class com.example.spark.WordCount --executor-memory 1G \
--total-executor-cores 2 /opt/wordcount.jar hdfs://hacluster/aa/hello.tx - 执行过程
Main类通过一个标准的建造者模式,传入参数,构建AbstractCommandBuilder最后传入env返回cmdList,通过对应系统的prepareCommand输出,由spark-class shell接收回参数1
2
3
4AbstractCommandBuilder builder;
if (className.equals("org.apache.spark.deploy.SparkSubmit")) {
try {
builder = new SparkSubmitCommandBuilder(args);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16List<String> cmd = builder.buildCommand(env);
if (printLaunchCommand) {
System.err.println("Spark Command: " + join(" ", cmd));
System.err.println("========================================");
}
if (isWindows()) {
System.out.println(prepareWindowsCommand(cmd, env));
} else {
// In bash, use NULL as the arg separator since it cannot be used in an argument.
List<String> bashCmd = prepareBashCommand(cmd, env);
for (String c : bashCmd) {
System.out.print(c);
System.out.print('\0');
}
}
- spark-class 执行最终的启动命令
1
2CMD=("${CMD[@]:0:$LAST}")
exec "${CMD[@]}"
至此,在shell端的代码执行完毕,spark程序进入真正运行的java端代码
日级别拉链表存储方案
背景
当前数仓表的生命周期策略数据生命周期管理规范,除个别表外,无条件对所有表采用93天快照策略,数据重复存储,造成存储压力大。
现状:共xxx张表,占用xxx张空间,平均每张xxx存储。
基于合理利用存储,控制存储无序扩展,节约公司存储成本,需要该表快照策略,由快照策略改为拉链策略。
说明
本方案所说拉链,指的是替换快照方式日粒度的存储拉链,有别于基于业务流水数据设计的拉链。
方案比较
快照vs拉链
简洁版
比较项 | 快照 | 拉链 |
---|---|---|
写入 | 无需加工 | 需要加工 |
使用 | 无成本 | 理解成本高 |
存储 | 126份副本 | 2~5份副本 |
计算 | 无 | 去重&排序 |
适用 | 所有 | 有主键&数据变更时间 |
明细版
比较项 | 快照 | 拉链 |
---|---|---|
写入 | 快照直接按数据日期写入,简单易懂 | 拉链需要结合当天最新数据和历史拉链数据加工出最新数据,略微复杂 |
使用 | 快照关联历史直接按数据日期取多版本,简单易懂 | 拉链需要根据业务日期和开始时间及结束时间比较,确定唯一版本,使用成本高 |
存储 | 快照为93天周期+每月最后一天,以3年为例,共计126份副本 | 拉链只有在数据变更才会重复存储,根据数据量变更频繁程度,预估2~5份副本 |
计算 | 无计算 | 需要根据id和创建时间和结束时间进行去重和排序,进而计算出开始时间和结束时间 |
适用 | 所有 | 需要有主键&数据变更时间 |
总结
快照方案简单粗暴有效,拉链方案复杂优雅有效。
加工和使用成本上,可以认为拉链是快照方案的2~5倍
存储成本上,可以任务拉链是快照方案的 1/30 之一
前提条件
并非所有的表都可以做成拉链表来存储历史记录,业务表必须满足一下几点方可设计拉链
条件 | 解释 | 现状 |
---|---|---|
有唯一主键id | 业务库必须有唯一主键id用于标识同一条记录 这样才能对同一条记录进行版本区分 |
开发规范里有明确必须有主键id 不排除个别表 |
有业务数据变更时间 | 如果数据字段发生变更,然而数据时间不进行变更会导致拉链表无法确认时间 | 开发规范里有明确edit_time需要自动更新 历史老表存在不更新现象,需要在mysql表结构中确认是否自动更新 |
设计
统一规范
1)无穷大的结束时间,统一采用 29991231 表示
2)无穷小的开始时间,统一采用 20000101表示
3)拉链表统一新增三个字段
之所以加上data前置,为了防止字段重名
字段名 | 解释 |
---|---|
data_start_date | 数据生效开始日期 |
data_end_date | 数据生效结束日期 |
data_is_active | 数据是否当前有效 |
4)拉链表分区统一使用三个字段进行分区 | |
其中data_start_year和data_end_year是为了加快使用效率 | |
dayid是为了获取昨天版本 | |
字段名 | 解释 |
———– | ———– |
data_start_year | 数据开始年份 |
data_end_year | 数据结束年份 |
dayid | 数据日期 |
5)data_start_date和data_end_date采用闭区间设计
6)拉链表的生命周期为2,即保留两份副本
7) 命名统一采用 xxx_fds命名
8)当前拉链表只针对dwd进行设计
设计举例
mysql 举例表结构
表名:test_a
字段 | 解释 | 其他 |
---|---|---|
id | 主键id | pk |
test_name | 测试名称 | |
create_time | 创建时间 | |
edit_time | 编辑时间 |
mysql 举例表数据
20210701数据
日期 | id | test_name | create_time | edit_time |
---|---|---|---|---|
20210701 | 1 | what’s your name | 20210701 | 20210701 |
20210701 | 2 | what’s your age | 20210701 | 20210701 |
2021072 | 1 | what’s wrong | 20210701 | 20210702 |
20210702 | 2 | what’s your age | 20210701 | 20210701 |
20210710 | 1 | whattttttttttt | 20210701 | 20210710 |
20210710 | 2 | what’s your age | 20210701 | 20210701 |
拉链表代码
1 | set hive.exec.dynamic.partition=true; |
拉链表数据效果
|数据日期| data_start_date| data_end_date| data_is_active| id| test_name| create_time| edit_time| data_start_year| data_end_year|
|—–| —–| —–| —–| —–| —–| —–| —–| —–| —–|
|20210701| 20210701| 29991231| 1| 1| what’s your name| 20210701| 20210701| 2021| 2999|
|20210701|20210701 |29991231 |1 |2 |what’s your age| 20210701| 20210701| 2021| 2999|
|20210702| 20210701| 20210701| 0| 1| what’s your name| 20210701| 20210701| 2021| 2021|
|20210702|20210702| 29991231| 1| 1| what’s wrong| 20210701| 20210702| 2021| 2999|
|20210702|20210701| 29991231| 1| 2| what’s your age| 20210701| 20210701| 2021| 2999|
|20210710| 20210701| 20210701| 0| 1| what’s your name| 20210701| 20210701| 2021| 2021|
|20210710|20210702| 20210709| 0| 1| what’s wrong| 20210701| 20210702| 2021| 2021|
|20210710|20210710| 29991231| 1| 1| whattttttttttt| 20210701| 20210710 |2021| 2999|
|20210710|20210701 |29991231 |1| 2| what’s your age| 20210701| 20210701| 2021| 2999|
拉链表的使用
获取当前最新数据
1)优先使用最新表而非快照表
2)一定要用快照: sql select * from dwd_test_a_fds where dayid='cur_time' and data_is_active=1
获取某一天的状态
1 | select * from dwd_test_a_fds |
根据业务字段字段进行匹配
1 | select a.* |
效果
待测试,暂定dwd_order_shop_full_d 表
流程
java基础问题 【转载】
变量
成员变量与局部变量的区别?
- 语法形式 :从语法形式上看,成员变量是属于类的,而局部变量是在代码块或方法中定义的变量或是方法的参数;成员变量可以被
public
,private
,static
等修饰符所修饰,而局部变量不能被访问控制修饰符及static
所修饰;但是,成员变量和局部变量都能被final
所修饰。 - 存储方式 :从变量在内存中的存储方式来看,如果成员变量是使用
static
修饰的,那么这个成员变量是属于类的,如果没有使用static
修饰,这个成员变量是属于实例的。而对象存在于堆内存,局部变量则存在于栈内存。 - 生存时间 :从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动生成,随着方法的调用结束而消亡。
- 默认值 :从变量是否有默认值来看,成员变量如果没有被赋初始值,则会自动以类型的默认值而赋值(一种情况例外:被
final
修饰的成员变量也必须显式地赋值),而局部变量则不会自动赋值。
转载
本文转自基础概念与常识
JUC下Atomic 原子类简介&常见问题 【转载】
java下的JUC是什么?
是 java jdk 包java.util.concurrent
的简称,jdk将并发多线程相关的类都放到该包下。
Atomic 原子类介绍
Atomic 翻译成中文是原子的意思。在化学上,我们知道原子是构成一般物质的最小单位,在化学反应中是不可分割的。在我们这里 Atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。
所以,所谓原子类说简单点就是具有原子/原子操作特征的类。
并发包 java.util.concurrent
的原子类都存放在java.util.concurrent.atomic
下,如下图所示。
根据操作的数据类型,可以将 JUC 包中的原子类分为 4 类
基本类型
使用原子的方式更新基本类型
AtomicInteger
:整型原子类AtomicLong
:长整型原子类AtomicBoolean
:布尔型原子类
数组类型
使用原子的方式更新数组里的某个元素
AtomicIntegerArray
:整型数组原子类AtomicLongArray
:长整型数组原子类AtomicReferenceArray
:引用类型数组原子类
引用类型
AtomicReference
:引用类型原子类AtomicStampedReference
:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于解决原子的更新数据和数据的版本号,可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。AtomicMarkableReference
:原子更新带有标记位的引用类型
对象的属性修改类型
AtomicIntegerFieldUpdater
:原子更新整型字段的更新器AtomicLongFieldUpdater
:原子更新长整型字段的更新器AtomicReferenceFieldUpdater
:原子更新引用类型字段的更新器
CAS ABA 问题
- 描述: 第一个线程取到了变量 x 的值 A,然后巴拉巴拉干别的事,总之就是只拿到了变量 x 的值 A。这段时间内第二个线程也取到了变量 x 的值 A,然后把变量 x 的值改为 B,然后巴拉巴拉干别的事,最后又把变量 x 的值变为 A (相当于还原了)。在这之后第一个线程终于进行了变量 x 的操作,但是此时变量 x 的值还是 A,所以 compareAndSet 操作是成功。
- 例子描述(可能不太合适,但好理解): 年初,现金为零,然后通过正常劳动赚了三百万,之后正常消费了(比如买房子)三百万。年末,虽然现金零收入(可能变成其他形式了),但是赚了钱是事实,还是得交税的!
- 代码例子(以
AtomicInteger
为例)
1 | import java.util.concurrent.atomic.AtomicInteger; |
输出内容如下:
1 | Thread-0 ------ currentValue=1 |
下面我们来详细介绍一下这些原子类。
基本类型原子类
基本类型原子类介绍
使用原子的方式更新基本类型
- AtomicInteger:整型原子类
- AtomicLong:长整型原子类
- AtomicBoolean :布尔型原子类
上面三个类提供的方法几乎相同,所以我们这里以 AtomicInteger 为例子来介绍。
AtomicInteger 类常用方法
1 | public final int get() //获取当前的值 |
AtomicInteger 常见方法使用
1 | import java.util.concurrent.atomic.AtomicInteger; |
基本数据类型原子类的优势
通过一个简单例子带大家看一下基本数据类型原子类的优势
① 多线程环境不使用原子类保证线程安全(基本数据类型)
1 | class Test { |
② 多线程环境使用原子类保证线程安全(基本数据类型)
1 | class Test2 { |
AtomicInteger 线程安全原理简单分析
AtomicInteger 类的部分源码:
1 | // setup to use Unsafe.compareAndSwapInt for updates(更新操作时提供“比较并替换”的作用) |
AtomicInteger 类主要利用 CAS (compare and swap) + volatile 和 native 方法来保证原子操作,从而避免 synchronized 的高开销,执行效率大为提升。
CAS 的原理是拿期望的值和原本的一个值作比较,如果相同则更新成新的值。UnSafe 类的 objectFieldOffset() 方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址。另外 value 是一个 volatile 变量,在内存中可见,因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值。
数组类型原子类
数组类型原子类介绍
使用原子的方式更新数组里的某个元素
- AtomicIntegerArray:整形数组原子类
- AtomicLongArray:长整形数组原子类
- AtomicReferenceArray :引用类型数组原子类
上面三个类提供的方法几乎相同,所以我们这里以 AtomicIntegerArray 为例子来介绍。
AtomicIntegerArray 类常用方法
1 | public final int get(int i) //获取 index=i 位置元素的值 |
AtomicIntegerArray 常见方法使用
1 |
|
引用类型原子类
引用类型原子类介绍
基本类型原子类只能更新一个变量,如果需要原子更新多个变量,需要使用 引用类型原子类。
- AtomicReference:引用类型原子类
- AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于解决原子的更新数据和数据的版本号,可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。
- AtomicMarkableReference :原子更新带有标记的引用类型。该类将 boolean 标记与引用关联起来,
也可以解决使用 CAS 进行原子更新时可能出现的 ABA 问题。
上面三个类提供的方法几乎相同,所以我们这里以 AtomicReference 为例子来介绍。
AtomicReference 类使用示例
1 | import java.util.concurrent.atomic.AtomicReference; |
上述代码首先创建了一个 Person 对象,然后把 Person 对象设置进 AtomicReference 对象中,然后调用 compareAndSet 方法,该方法就是通过 CAS 操作设置 ar。如果 ar 的值为 person 的话,则将其设置为 updatePerson。实现原理与 AtomicInteger 类中的 compareAndSet 方法相同。运行上面的代码后的输出结果如下:
1 | Daisy |
AtomicStampedReference 类使用示例
1 | import java.util.concurrent.atomic.AtomicStampedReference; |
输出结果如下:
1 | currentValue=0, currentStamp=0 |
AtomicMarkableReference 类使用示例
1 | import java.util.concurrent.atomic.AtomicMarkableReference; |
输出结果如下:
1 | currentValue=null, currentMark=false |
对象的属性修改类型原子类
对象的属性修改类型原子类介绍
如果需要原子更新某个类里的某个字段时,需要用到对象的属性修改类型原子类。
- AtomicIntegerFieldUpdater:原子更新整形字段的更新器
- AtomicLongFieldUpdater:原子更新长整形字段的更新器
- AtomicReferenceFieldUpdater :原子更新引用类型里的字段的更新器
要想原子地更新对象的属性需要两步。第一步,因为对象的属性修改类型原子类都是抽象类,所以每次使用都必须使用静态方法 newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。第二步,更新的对象属性必须使用 public volatile 修饰符。
上面三个类提供的方法几乎相同,所以我们这里以 AtomicIntegerFieldUpdater
为例子来介绍。
AtomicIntegerFieldUpdater 类使用示例
1 | import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; |
输出结果:
1 | 22 |