在负#if #endif语句之间的块是不可见的。负#if #endif语句是条件编译的一种形式,用于在编译时根据条件选择性地包含或排除代码块。在反编译后,编译时的条件判断已经失去了意义,因此负#if #endif语句之间的代码块将被完全展开,不再受条件限制,即使在源代码中该代码块是被排除的,也会在反编译后变为可见。这意味着反编译后的代码中将包含负#if #endif语句之间的所有代码。
前言 在《【高并发】如何解决可见性和有序性问题?这次彻底懂了!》一文中,我们了解了Java是如何解决多线程之间的可见性和有序性问题。...也就是说,在同一时刻只有一个线程在执行!如果我们能够保证对共享变量的修改是互斥的,那么,无论是单核CPU还是多核CPU,都能保证多线程之间的原子性了。...从反编译的结果来看,synchronized在run()方法中修饰代码块时,使用了monitorenter 和monitorexit两条指令,如下所示。...但是,还没完,TestCount类中还有一个getCount()方法,如果执行了incrementCount()方法,count变量的值对getCount()方法是可见的吗?...所以,修改后的代码会存在并发问题。 我们也可以使用下图来简单的表示这个逻辑。 ? 总结 保证多线程之间的互斥性。也就是说,在同一时刻只有一个线程在执行!
有 5 种常见的分界符: {{ 变量 }},将变量放置在 {{ 和 }} 之间; {% 语句 %},将语句放置在 {% 和 %} 之间; {# 注释 #},将注释放置在 {# 和 #} 之间; ## 注释...for 语句 语法 jinja2 模板中,使用 {% 语句 %} 包围的语法块称为语句,jinja2 支持类似于 Python 的 for 循环语句,语法如下: {% for item in iterable...能看到 # for 的写法并没有生效 if 语句 语法 jinja2 模板中,使用 {% 语句 %} 包围的语法块称为语句,jinja2 支持类似于 Python 的 if-else 判断语句,语法如下... 过滤器 语法 jinja2 过滤器的是一个函数,语法如下: {{ variable | filter }} 执行函数调用 filter(varialbe),把函数返回值作为这个代码块的值...= 'hello' 渲染后的 html HELLO
2022-12-02:有a块草莓蛋糕,有b块芝士蛋糕,两人轮流拿蛋糕, 每次不管是谁只能选择在草莓蛋糕和芝士蛋糕中拿一种, 拿的数量在1~m之间随意, 谁先拿完最后的蛋糕谁赢。...1.a==b 蛋糕一样多 先手必输,因为先手不管拿什么,拿多少 后手都在另一堆上,拿同样多的蛋糕 继续让两堆蛋糕一样多 最终先手必输,后手必赢 2.a!=b 如果 a !...= b 关注a和b的差值, 谁最先遇到差值为0,谁输 那么这就是巴什博奕 差值蛋糕数量共rest个。 每次从最少取1个,最多取m个,最后取光的人取胜。 如果rest=(m+1)*k + s (s!...("测试结束"); } // 草莓蛋糕a块 // 巧克力蛋糕b块 // 每次可以在任意一种上拿1~m块 // 返回谁会赢,"先手" or "后手" static mut dp: [[[&str; 101...= b // 关注a和b的差值, // 谁最先遇到差值为0,谁输 // 那么这就是巴什博奕 // 差值蛋糕数量共rest个。
,它的使用解决了并发多线程中的三大问题:原子性、可见性、顺序性。...问题1:synchronized修饰代码块可以给类加锁吗? 当然可以!我们前面说了修饰代码块时,是给代码中的对象加锁,这里面的对象既可以是实例也可以是类。...synchronized的底层原理 在synchronized的底层(JVM层面),针对方法与代码块的实现逻辑是不同的,因此我们在分析底层原理时也要分别来看。...class文件进行反编译后,分析其底层实现。...知识点扩展:我们通过javap命令进行反编译,javap是Java class文件分解器,可以反编译,也可以查看java编译器生成的字节码等。
前言 volatile 是 Java 并发编程中一个非常重要,也是面试常问的一个技术点,用起来很简单直接修饰在变量前面即可,但是我们真的懂这个关键字吗?...这说明 volatile 实现了多线程之间变量的可见性。 很多人喜欢用上面的例子来说明 volatile ,真的这么简单吗?这个结论正确吗?...也就是说只要我们给 CPU 让出一点点时间片,默认的缓存一致性协议就能帮我们实现可见性,比如休眠,哪怕是 1ms,或者加一行输出语句(因为输出语句涉及到 IO 操作,IO 操作是 CPU 委托给 DMA...然后我们说 volatile 实现可见性这个结论肯定是没错的,但是它实现的是基于 JMM 内存规范上的可见性,就是说这是 JMM 层面的,在 CPU、高速缓存、主内存之间的可见性是通过缓存一致性协议去实现的...CPU 内存屏障 内存屏障, 是一类同步屏障指令,是CPU或编译器在对内存随机访问的操作中的一个同步点,使得此点之前的所有读写操作都执行后才可以开始执行此点之后的操作。
# 1.2 自动拆箱和自动装箱 自动拆箱和自动装箱是一种语法糖,它说的是八种基本数据类型的包装类和其基本数据类型之间的自动转换。...我们反编译看一下 我们可以看到,我们明明是使用了 if …else 语句,但是编译器却只为我们编译了 DEBUG = true 的条件, 所以,Java 语法的条件编译,是通过判断条件为常量的 if...# 1.9 断言 你在 Java 中使用过断言作为日常的判断条件吗? 断言:也就是所谓的 assert 关键字,是 jdk 1.4 后加入的新功能。...它主要使用在代码开发和测试时期,用于对某些关键数据的判断,如果这个关键数据不是你程序所预期的数据,程序就提出警告或退出。当软件正式发布后,可以取消断言部分的代码。它也是一个语法糖吗?...新的声明包含三部分:try-with-resources 声明、try 块、catch 块。
自动拆箱和自动装箱 自动拆箱和自动装箱是一种语法糖,它说的是八种基本数据类型的包装类和其基本数据类型之间的自动转换。...我们反编译看一下 image 我们可以看到,我们明明是使用了 if ...else 语句,但是编译器却只为我们编译了 DEBUG = true 的条件, 所以,Java 语法的条件编译,是通过判断条件为常量的...断言 你在 Java 中使用过断言作为日常的判断条件吗? 断言:也就是所谓的 assert 关键字,是 jdk 1.4 后加入的新功能。...它主要使用在代码开发和测试时期,用于对某些关键数据的判断,如果这个关键数据不是你程序所预期的数据,程序就提出警告或退出。当软件正式发布后,可以取消断言部分的代码。它也是一个语法糖吗?...新的声明包含三部分:try-with-resources 声明、try 块、catch 块。
自动拆箱和自动装箱 自动拆箱和自动装箱是一种语法糖,它说的是八种基本数据类型的包装类和其基本数据类型之间的自动转换。...我们可以看到,我们明明是使用了 if …else 语句,但是编译器却只为我们编译了 DEBUG = true 的条件, 所以,Java 语法的条件编译,是通过判断条件为常量的 if 语句实现的,编译器不会为我们编译分支为...断言 你在 Java 中使用过断言作为日常的判断条件吗? 断言:也就是所谓的 assert 关键字,是 jdk 1.4 后加入的新功能。...它主要使用在代码开发和测试时期,用于对某些关键数据的判断,如果这个关键数据不是你程序所预期的数据,程序就提出警告或退出。当软件正式发布后,可以取消断言部分的代码。它也是一个语法糖吗?...新的声明包含三部分:try-with-resources 声明、try 块、catch 块。
对象锁与类静态方法之间无锁冲突。类锁与对象方法也没有锁冲突。类锁的作用域为这个类所有的类锁。 Q3:对于对象 Sync x 和 对象 Sync y哪些语句可以同时执行? ...同时,这也解释了为什么不同对象的对象锁之间为何互不影响: 因为对象锁的原理是基于单个对象的头部的锁信息。 synchronized 在锁的实现上相对复杂,存在着不同锁类型的切换升级。...synchronized 的内存可见性 需要特别注意的事是, 根据JMM的规范, synchronized 块里面的对象, 具有内存可见性。...反编译字节码可以发现: javap -v -p -s -sysinfo -constants XXXX.class 它依赖的是monitorenter和monitorexit指令, 他们在JVM里的实现...轻量级锁 在偏向锁升级为轻量级锁后。 竞争失败的锁可能采用自旋的方式, 在N次自旋中尝试获取锁,此时所有的竞争线程都平等。因此synchronized是非公平锁。
--[if IE]>此处内容只有IE可见 此处内容只有IE6.0可见 此处内容只有非IE可见 常见浏览器兼容性问题与解决方案?...块属性标签float后,又有横行的margin情况下,在IE6显示margin比设置的大 问题症状:常见症状是IE6中后面的一块被顶到下一行。...在用float布局并有横向的margin后,在IE6下,他就具有了块属性float后的横向margin的bug。...示意图: image.png 外边距重叠的意义 外边距的重叠只产生在普通流文档的垂直外边距之间,避免块级元素之间产生双倍边距的问题。 外边距重叠解决方案 1.
元素一旦浮动起来后,都将变成块级元素 块级:允许修改尺寸,允许设置上下 margin 行内元素:不能改尺寸,不能设置上下 margin ④....行内块元素,文本采用的是环绕的排列方式,无法被浮动元素压在底下 43....主轴终点对齐 C. center 居中对齐 D. space-between 两端对齐,项目之间的距离是相等的 E. space-around 每个项目两侧间距是相等的,注意:项目与项目之间的间隔,要比项目与父元素之间的间隔大一倍...语句示例 A. 只在 IE 下生效 这段文字只在 IE 浏览器显示 B. 只在 IE6 下生效 这段文字在非 IE8 浏览器显示 E. 非 IE 浏览器生效 这段文字只在非 IE 浏览器显示 F.
根据经验,try-finally语句是确保资源会被关闭的最佳方法,就算异常或者返回也一样。...但是在 try-with-resources 结构中,异常处理也有两种情况(注意,不论 try 中是否有异常,都会首先自动执行 close 方法,然后才判断是否进入 catch 块,建议阅读后面的反编译代码...try 块发生异常,然后自动调用 close 方法,如果 close 也发生异常,catch 块只会捕捉 try 块抛出的异常,close 方法的异常会在catch 中被压制,但是你可以在catch块中...如果有疑问的话,那么先来看一下上面这段代码反编译之后的结果吧 反编译后的执行过程 public static void startTest() { try { MyAutoCloseA a...,也就是说,在创建完成 a 和 b 对象后,对 a 调用test() 方法,会先输出A 的信息,然后抛出异常进行关闭,自动调用 close() 方法,执行关闭的顺序是从后向前执行,所以会先关闭 b 的对象
上图是IDA逆向工具反编译结果,相比UE的“暴力”,这个非常人性化,在第三节中重点介绍该软件的一些知识。...4、默认的读/写数据块,全局变量,静态变量一般放在这个区段。 ?...返回语句通常用于函数调用过程中的函数返回。 为深入理解掌握各类控制语句在反编译结果的形态,现编写各类控制语句的源码,生成对应程序,再利用IDA反编译,观察其形态。...2、Switch语句 源代码: int a; 反编译结果: text:00401009 push offset Format ; "%d" 反编译结果可见,switch语句也进行了同样优化,多个分支共同调用同一处...结合上图,可见在401362处push 0即为参数uType的值。
反编译后内容如下: ? 看到这个代码,你知道原来字符串的switch是通过equals()和hashCode()方法来实现的。还好hashCode()方法返回的是int,而不是long。...首先,我们发现,在反编译后的代码中没有System.out.println("Hello, ONLINE!");,这其实就是条件编译。...糖块九 、 数值字面量 在java 7中,数值字面量,不管是整数还是浮点数,都允许在数字之间插入任意多个下划线。这些下划线不会对字面量的数值产生影响,目的就是方便阅读。 比如: ? 反编译后: ?...反编译后就是把_删除了。也就是说编译器并不认识在数字字面量中的_,需要在编译阶段把他去掉。...关闭资源的常用方式就是在finally块里是释放,即调用close方法。比如,我们经常会写这样的代码: ?
所谓thread local变量,就是对于同一个变量,每个线程都有自己的一份,对该变量的访问是线程隔离的,它们之间不会相互影响,所以也就不会有各种多线程问题。...但你知道吗,不仅是在编程语言中,在linux内核中,也有一个类似的机制,用来实现类似的目的,它叫做percpu变量。...this_cpu_read_stable方法其实也是一个宏,它全部展开后是下面这个样子: ? 在这里,我们先不讲宏展开后各语句到底是什么意思,我们先跑个题。...当然,我们还可以通过反编译的方式,进一步确认下宏展开后确实是这样: ? 由上可见,宏展开后其实主要就是一条mov指令,其中current_task变量地址的值为0x16d00。...好,我们回到上文中断的部分,来继续看下get_current方法里宏展开后各语句的意思。
后来又出现了「自定义 Linker」等方式的保护方式,这样可以隐藏一些文件格式信息,但依旧解决不了函数被Dump后的反编译问题。...虽然使用OLLVM进行保护后,可以在一定程度上起到防止反编译的作用,但依旧存在很多问题。...可以被反编译 由于 OLLVM 是在编译过程中对 LLVM IR 进行了处理,IR 属于架构无关指令,在 LLVM 后端依然要生成平台相关的指令,所以最终只是变成了「更加复杂的 C/C++ 代码」而已。...函数间引用关系可见 混淆对象受限于 IR 指令,无法精细的对 Native 指令进行操作,使得保护后的代码仍然可以被反编译工具用 「交叉引用」 搜索到,对函数间调用关系的保护效果差。...无函数边界 通过链接器乱序再重定位,生成的指令块在可执行文件中的位置是随机的,函数保护后变成了无数个随机位置的指令碎片,无法知道函数的边界。
这三个特征可谓是整个Java并发的基础。 原子性 原子性指的是一个操作是不可分割,不可中断的,一个线程在执行时不会被其他线程干扰。 面试官拿笔写了段代码,下面这几句代码能保证原子性吗?...因此在 synchronized 块之间的操作都是原子性的。 ---- 可见性 可见性指当一个线程修改共享变量的值,其他线程能够立即知道被修改了。Java是利用volatile关键字来提供可见性的。...synchronized的原理是,一个线程lock之后,必须unlock后,其他线程才可以重新lock,使得被synchronized包住的代码块在多线程之间是串行执行的。...所以语句3不能放在语句1、2前,也不能放在语句4、5后。但是语句1、2的顺序是不能保证的,同理,语句4、5也不能保证顺序。...并且,执行到语句3的时候,语句1,2是肯定执行完毕的,而且语句1,2的执行结果对于语句3,4,5是可见的。
其中Cecil负责分析类型 类成员关系 ,比如类字段函数结构,引用关系、类之间的继承关系等,ILSpy负责反编译函数体里的语句,比如条件语句,函数调用,算数运算等。下面逐个介绍具体的实现。...反编译嵌入自定义逻辑代码,实现了原生代码功能的更新。也就是说在没有源代码的前提下,Mono.Ceil可以动态嵌入指定代码至可执行文件。...png] 上面是C#逻辑打包成dll后,采用Cecil反编译得到的内容如下,具体逻辑见注释: [8.png] 用Mono.Cecil得到了二进制文件的中间代码,中间代码是一种基于操作栈的虚拟机语言,指令间借助栈传递数据...对IL Instructions以跳转指令为界限,划分了基本的block,block间构成树形结构: [12.png] TK_CSLua ======== TK_CSLua根据不同的语句块实现具体的翻译逻辑...翻译过程是一个递归的过程,如图为不同类型的语句块处理逻辑: [13.png] while循环的处理逻辑为: [14.png] 最终自动生成了Lua代码,如下所示: [15.png] ToLua ====
块中包含return语句,则不会对try块中要返回的值进行保护,而是直接跳到finally语句中执行,并最后在finally语句中返回,返回值是在finally块中改变之后的值; finally 为什么一定会执行...原来是JVM为了保证所有异常路径和正常路径的执行流程都要执行finally中的代码,所以在try和catch后追加上了finally中的字节码指令,再加上它自己本身的指令,正好三次。...请看 在正常情况下,它是一定会被执行的,但是至少存在以下三种情况,是一定不执行的: try语句没有被执行到就返回了,这样finally语句就不会执行,这也说明了finally语句被执行的必要而非充分条件是...class文件后的异常表信息如下: from:代表异常处理器所监控范围的起始位置; to:代表异常处理器所监控范围的结束位置(该行不被包括在监控范围内,是前闭后开区间); target:指向异常处理器的起始位置...最坏的情况下JVM需要遍历该线程 Java 栈上所有方法的异常表; 拿第一行为例:如果位于2-4行之间的命令(即try块中的代码)抛出了Class java/lang/Exception类型的异常,则跳转到第
领取专属 10元无门槛券
手把手带您无忧上云