【线程安全篇】
线程安全之原子性问题
x++ ,在字节码文件中对应多个指令,多个线程在运行多个指令时,就存在原子性、可见性问题
赋值
多线程场景下,一个指令如果包含多个字节码指令,那么就不再是原子操作。因为赋值的同时,读到的x的值可能已经发生变化,被其他线程修改了。
x = 10; //原子操作,只有一个操作,10赋值给x,之后写入内存y = x; //非原子操作,1、先从内存读x的值 2、x的值赋值给y,再写入内存x++; //非原子操作,同上
count++
模拟多个线程count++,最终count不一定等于1000。
public class Demo{ private static int count=0; public static void inc(){ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } count++; } public static void main(String[] args) throws InterruptedException {for(int i=0;i<1000;i++){ new Thread(()->Demo.inc()).start(); } Thread.sleep(3000); System.out.println("运行结果"+count); }
}
线程安全之可见性问题
多个线程访问同一变量,一个线程修改了该变量的值,其他线程能立刻看到修改的最新值。
CPU缓存不一致问题
计算机核心组件:CPU、内存、I/O设备
计算速度对比:CPU > 内存 > I/O设备
为了提升计算性能,CPU从单核升级到了多核,以及超线程技术。但后两者的处理性能并没有跟上。为了平衡三者的速度差异,做了很多优化:
1.CPU增加了高速缓存,很好的解决了CPU和内存的速度矛盾。
2.操作系统增加了进程、线程。通过CPU时间片切换最大化提高CPU录用率。
3.编译器指令优化。
CPU高速缓存
线程是CPU调度的最小单元。
主内存 、总线 、CPU多级缓存
CPU先在L1找数据,L1没有去L2,L2没有去L3,L3没有去内存找。
CPU计算时,直接从缓存中读取数据,计算完成后再写入缓存中,最后再把缓存中的数据同步到内存。
缓存不一致问题
每个CPU拥有自己的缓存,如果同一数据在不同缓存中,缓存值不一样,就存在缓存不一致的问题。
解决方案: 总线锁、缓存锁
总线锁
当一个CPU要对共享变量操作时,在总线上发出LOCK#信号,锁住CPU和内存的通信,锁住期间,其他CPU不能操作缓存了该数据内存地址的缓存。
总线锁开销比较大,所以这种机制显然不合适。
缓存锁
基于缓存一致性协议
缓存一致性协议(MESI)
M(Modify)
被修改的。该数据只在当前CPU的缓存中有,且与主内存不一致。
E(Exclusive)
独占的。该数据只在当前CPU缓存中,且没有被修改过。
S(Shared)
共享的。该数据被多个CPU缓存,且各缓存中的数据与主内存一直。
I(Invalid)
失效的。当前CPU中缓存的该数据失效。
i=1,该CPU独占且与内存数据一致,此时处于E状态,如果i变成了2,则状态变为M。
CPU只能从缓存中读取M、E、S状态的数据,I状态的数据要到内存中读取。
CPU可以直接写M、E状态的数据。S状态的数据,需要先将其他CPU中缓存行设置为无效才能写。
Store Bufferes
CPU0对缓存中的共享变量写入时,先发送一个失效的消息给到缓存了该共享变量的CPU,并且要等到它们的确认回执。这个过程中,CPU0处于阻塞状态。为了避免浪费资源,所以引入Store Bufferes
1.CPU0将数据写入Store Bufferes中,同时发送invalidate消息给CPU1,之后就可以继续处理其他指令。
2.CPU1收到invalidate消息后,将要修改的变量i放入invalidate queue(失效队列中),并且给一个ACK应答。
3.CPU0收到CPU1的invalidate acknowledge之后,将Store Bufferes中的数据存储至缓存行(cache line),最后再从缓存行同步到内存。
内存屏障(memory barrier)
内存屏障就是把Store Bufferes中的指令写入内存,内存屏障之前的内存访问操作先于其后的操作完成。保证共享变量对其他线程的可见性。
写屏障(store memory barrier)
store之前的所有已经存储在Sotre Bufferes中的数据同步到内存。即将Sotre Bufferes中的a==1同步到内存后,才能执行后面的b=1。
读屏障(load memory barrier)
load之后的读操作,都在load屏障之后执行。配合store屏障,使得store之前的写操作对load之后的读操作是可见的。
全屏障(full memory barrier)
full前的读写操作同步到内存后,才能执行full之后的操作。
重排序问题
为了提升性能,编译器和CPU会对指令做重排序,源码到最终执行,会经过三种重排序
注:2、3属于CPU重排序
JMM(Java Memory Model)
JMM定义了共享内存中,多线程的读写操作规范。实现了将共享变量存储到内存、从内存中取出共享变量的底层细节。从而解决CPU多级缓存、处理器优化、指令重排序导致的内存访问问题。保证了并发场景下的可见性。
缓存一致性问题,有总线索、缓存锁,缓存锁基于MESI协议。
指令重排序问题,硬件层面提供了内存屏障。
JMM在此基础上提供了volatile、final等关键字,来解决可见性、重排序问题。
内存屏障分4类
HappenBefore
如果前一个操作的结果需要另一个操作时可见,那么这两个操作之间必须存在happens-before关系。这两个操作可以是同一个线程,也可以是不同线程。
1、程序顺序规则(as-if-serial语义)==
单个线程中的代码顺序不管怎么变,对于结果来说是不变的。
依赖问题,如果两个指令存在依赖关系,不许重排序。
1 happenns-before 2,3 happens-before 4
2、volatile变量规则
volatile修饰的变量,写操作一定happens-before读操作。
2 happens-before 3
3.传递性规则
如果1 happenns-before 2,3 happens-before 4,那么1 happenns-before 4。
4.Start规则
线程A 中ThreadB.start()操作happenns-before线程B中的任意操作。
public StartDemo{
int x=0;
Thread t1 = new Thread(()->{
// 子线程中,x==10
});
x = 10; // 此处对共享变量 x 修改,此操作对于子线程可见。
t1.start(); // 主线程启动子线程
}
5.join规则
线程A中ThreadB.join(),那么线程B的所有操作happenns-before线程的ThreadB.join()操作。
public StartDemo{ int x=0; Thread t1 = new Thread(()->{ // 子线程中,x==10 x=100; //修改X}); x = 10; // 此处对共享变量 x 修改,此操作对于子线程可见。t1.start(); // 主线程启动子线程t1.join(); //子线程的修改,在主线程执行t1.join()之后皆可见。X==100
}
6.监视器锁的规则
解锁happenns-before下一个加锁。
synchronized (this) { // 此处自动加锁 if (this.x < 12) { // x 是共享变量, 初始值 =10 this.x = 12; }
} // 此处自动解锁
线程A中x = 12,那么线程B拿到锁之后,能看到x == 12。
Synchronized
synchronized可以解决线程原子性问题,synchronized块之间的操作具备原子性。
Java SE 1.6优化了synchronized,引入了偏向锁、轻量级锁,减少获得锁、释放锁带来的性能开销。
public class Demo{ private static int count=0; public static void inc(){ synchronized (Demo.class) { //基于Demo对象的生命周期来控制锁粒度try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } count++; }} public static void main(String[] args) throws InterruptedException {for(int i=0;i<1000;i++){ new Thread(()->Demo.inc()).start(); } Thread.sleep(3000); System.out.println("运行结果"+count); }
}
对象锁
synchronized 修饰方法
synchronized 修饰代码块 this/Synchronized_demo.this
多线程跑同一个对象
全局锁/类锁
synchronized 修饰 static 方法
各线程之间 抢锁
synchronized 修饰代码块 Synchronized_demo.class
各线程之间 抢锁
对象
对象的存储布局
对象头
包含了Mark Word、class指针、数组的长度(对象为数据时才有)
Mark Word(自身运行时数据)记录了对象和锁有关的信息。
32位操作系统为例:
synchronized 锁升级
所以在JDK1.6之后,synchronized中,锁存在4种状态:无锁、偏向锁、轻量级锁、重量级锁,锁状态由低到高不断升级。
偏向锁
大部分情况下,锁总被同一个线程多次获得,所以引入偏向锁。
对象头中存储线程ID,从而避免同一个线程再次进入、退出时获取锁、释放锁的操作。
如果多个线程竞争该锁,那么偏向锁就是一种累赘,可通过JVM参数UseBiasedLocking 来设置开启或关闭偏向锁。
偏向锁获取逻辑
1.获取锁对象的Mark Word,判断是否处于可偏向状态。
(biased_lock=1且 ThreadID 为空,则表示可偏向)
2.如果是可偏向状态,则通过CAS操作,把当前线程ID写入锁对象的Mark Word。
1)CAS成功,则获得偏向锁
2)CAS失败,说明偏向锁被其他线程占有,当前锁存在竞争,则撤销偏向锁,升级成轻量级锁。
3.如果是已偏向状态,则检查锁对象的Mark Word中的ThreadID 与当前线程的 ThreadID 是否相等。
1)如果相等,则无需再获得锁。
2)如果不相等,说明当前锁偏向于其他线程,要么重新偏向,要么撤销偏向锁,升级成轻量级锁。
偏向锁撤销逻辑
1.如果原获得偏向锁的线程同步代码块执行完了,那么锁对象设置成无锁状态,再重新偏向。
如果没有执行完,则在一个安全点停止拥有锁的线程A,修复锁记录和Mark Word,使其变成无锁状态,再唤醒线程A,将当前锁升级成轻量级锁。
轻量级锁
升级为轻量级锁之后,对象的Mark Word也会相应的变化。
轻量级锁的加锁逻辑
1.线程在自己的栈帧中创建锁记录LockRecord。
2.将锁对象 对象头中的MarkWord复制到线程刚刚创建的LockRecord。
3.将锁记录中的owner指针指向锁对象。
将锁对象对象头的MarkWord替换为指向锁记录的指针。
轻量级锁的解锁
锁释放逻辑其实就是获得锁的逆向逻辑。
通过CAS操作把线程栈帧中的LockRecord替换回到锁对象的MarkWord中,如果成功,表示没有竞争。如果失败,表示当前锁存在竞争,膨胀称为重量级锁。
自旋锁
轻量级锁在加锁的过程中,使用了自旋锁。
当一个线程来竞争锁时,会原地循环等待,直到锁被释放后,该线程直接获得锁,所以轻量级锁适用于同步代码块执行很快的场景。
自旋必须要一定的条件限制,否则不断循环,反而消耗CPU资源。默认情况下,自旋次数10次,可以通过preBlockSpin修改。
JDK1.6之后,引入自适应自旋锁,可根据前一次自旋时间以及锁拥有者的状态来觉得自旋次数。
重量级锁
当轻量级锁膨胀到重量级锁,未抢到锁的线程只能被挂起阻塞,等待被唤醒。
重量级锁是依赖对象内部的monitor锁来实现的,而monitor锁又依赖操作系统的MutexLock(互斥锁),所以重量级锁又称互斥锁。
当线程要去执行一段被synchronize修饰的方法或代码块时,需要先获得被synchronize修饰的对象的monitor监视器(monitorenter),获取失败,线程进入同步队列,变成blocked状态,直到锁被释放之后,当前线程会被唤醒,重新尝试对monitorenter的获取。
synchronized的执行过程
- 检测Mark Word里面是不是当前线程的ID,如果是,表示当前线程处于偏向锁 。
- 如果不是,则使用CAS将当前线程的ID替换Mard Word里的线程ID,如果成功则表示当前线程获得偏向锁,置偏向标志位1 ,如果失败,则说明发生竞争,撤销偏向锁,进而升级为轻量级锁。
- 当前线程使用CAS将对象头的Mark Word替换为锁记录指针,如果成功,当前线程获得锁 ,如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
- 如果自旋成功则依然处于轻量级,如果自旋失败,则升级为重量级锁。
sleep
Thread.sleep(1000)
阻塞1秒,期间不释放锁
wait
wait()阻塞当前线程,释放锁,并把当前线程放入等待队列,等待被唤醒。
wait()前提是必须先获得锁,这样才能释放锁,一般配合synchronized 关键字使用,即一般在synchronized 同步代码块里使用 wait()、notify/notifyAll() 方法。
public class ThreadA extends Thread{private Object lock;public ThreadA(Object lock) {this.lock = lock;}@Overridepublic void run() {synchronized (lock){System.out.println("start ThreadA");try {lock.wait(); //实现线程的阻塞,并且释放锁} catch (InterruptedException e) {e.printStackTrace();}System.out.println("end ThreadA");}}
}
notify
notify()是将锁交给含有wait()方法的线程,让其继续执行下去,所以必须先持有锁
public class ThreadB extends Thread{private Object lock;public ThreadB(Object lock) {this.lock = lock;}@Overridepublic void run() {synchronized (lock){System.out.println("start ThreadB");lock.notify(); //唤醒被阻塞的线程System.out.println("end ThreadB");}}
}
notifyAll
notifyAll()唤醒等待队列里的线程,等待队列并没有资格竞争锁,而是线程被移到同步队列后,再竞争锁。
jion
主线程合并子线程。join底层是使用wait()来实现,所以会释放锁。
Volatile
Vloatile遵循HappenBefore规则,能保证新值在修改后立即同步回主内存,每次使 用前从主内存刷新。
普通变量无法保证这一点,因为普通的共享变量修改后,什么时候同步写回主内存是不确定的,其他线程读取时,内存中可能还是原来的旧值。
public class App {public volatile static boolean stop=false;public static void main( String[] args ) throws InterruptedException {Thread t1=new Thread(()->{int i=0;while(!stop){ //condition 不满足i++;}System.out.println(i);});t1.start();Thread.sleep(10);stop=true; //true 主线程设置stop为true,对子线程可见。}
}
final关键字提供了内存屏障的规则
相关文章:
【线程安全篇】
线程安全之原子性问题 x ,在字节码文件中对应多个指令,多个线程在运行多个指令时,就存在原子性、可见性问题 赋值 多线程场景下,一个指令如果包含多个字节码指令,那么就不再是原子操作。因为赋值的同时,…...
错误:EfficientDet网络出现“No boxes to NMS“并且mAP:0.0的解决方案
近日,在使用谷歌新推出来的一个网络EfficientDet进行目标检测训练自己的数据集的时候,出现了如下错误: 其中项目开源地址是:https://github.com/toandaominh1997/EfficientDet.Pytorch 上面截图中的1和2代表我的类别名称。读者可…...
python的opencv操作记录13——区域生长及分水岭算法
文章目录图像区域基本算法——形态学运算腐蚀与膨胀开运算与闭运算opencv中的形态学运算距离计算——distanceTransform函数连通域连通的定义计算连通域——connectedComponents连通域实验基于区域的分割区域生长算法自定义一个最简单区域生长算法实现区域分割一般区域分割open…...
一文看懂网上下单的手机流量卡为什么归属都是随机的!
最近很多网上下单的小伙伴们心中似乎都有一个疑问。那就是网上很多手机卡、流量卡都不能自选号码和归属地,就算能自选号码,归属地也是随机的而且很多都不会跟你说具体的城市,这是为什么呢?莫非其中有什么不可告人的秘密吗?小伙伴…...
python Pytest生成alluer测试报告的完整教程
1.下载allure包到本地,解压 网上很多资料,这边不提供了 2.配置环境变量 将上面解压后bin文件的路径复制,添加到环境变量Path下 3.验证环境变量配置是否功 在cmd中输入allure,回车 。查看allure是否成功: 4.pyc…...
4-spring篇
ApplicationContext refresh的流程 12个步骤 prepareRefresh 这一步创建和准备了Environment对象,并赋值给了ApplicationContext的成员变量 要理解Environment对象的作用 obtainFreshBeanFactory ApplicationContext 里面有一个成员变量,Beanfactory b…...
提升 Web 应用程序的性能:如何使用 JavaScript 编写缓存服务
缓存是一种重要的优化技术,用于加速数据访问和降低服务器负载。缓存存储经常访问的数据,以便在需要时可以快速检索。在本文中,我们将探索如何使用简单的数据结构在 JavaScript 中编写缓存服务。 编码缓存服务的第一步是定义将用于访问缓存的…...
供应商绩效管理指南:挑战、考核指标与管理工具
管理和优化供应商绩效既关键又具有挑战性。要知道价格并不是一切,如果你的供应商在商定的价格范围内向你开具发票,但服务达不到标准或货物不合格,你也无法达到节约成本的目标。 供应商绩效管理可以深入了解供应商可能带来的风险,…...
干货文稿|详解深度半监督学习
分享嘉宾 | 范越文稿整理 | William嘉宾介绍Introduction to Semi-Supervised Learning传统机器学习中的主流学习方法分为监督学习,无监督学习和半监督学习。这里存在一个是问题是为什么需要做半监督学习?首先是希望减少标注成本,因为目前可以…...
信箱|邮箱系统
技术:Java、JSP等摘要:在经济全球化和信息技术飞速发展的今天,通过邮件收发进行信息传递已经成为主流。目前,基于B/S(Browser/Server)模式的MIS(Management information system)日益…...
JS数组拓展
1、Array.from Array.from 方法用于将两类对象转为真正的数组: 类似数组的对象,所谓类似数组的对象,本质特征只有一点,即必须有length属性。 因此,任何有length属性的对象,都可以通过Array.from方法转为数组 和 可遍历…...
一道很考验数据结构与算法的功底的笔试题:用JAVA设计一个缓存结构
我在上周的笔试中遇到了这样一道题目,觉得有难度而且很考验数据结构与算法的功底,因此Mark一下。 需求说明 设计并实现一个缓存数据结构: 该数据结构具有以下功能: get(key) 如果指定的key存在于缓存中,则返回与该键关联的值&am…...
(10)C#传智:命名空间、String/StringBuilder、指针、继承New(第10天)
内容开始多了,慢品慢尝才有滋味。 一、命名空间namespace 用于解决类重名问题,可以看作类的文件夹. 若代码与被使用的类,与当前的namespace相同,则不需要using. 若namespace不同时,调用的方法:…...
基于Jetson Tx2 Nx的Qt、树莓派等ARM64架构的Ptorch及torchvision的安装
前提 已经安装好了python、pip及最基本的依赖库 若未安装好点击python及pip安装请参考这篇博文 https://blog.csdn.net/m0_51683386/article/details/129320492?spm1001.2014.3001.5502 特别提醒 一定要先根据自己板子情况,找好python、torch、torchvision的安…...
MySQL存储引擎详解及对比和选择
什么是存储引擎? MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。通过选择不同的技术,你能够获得额外的速度或者功能,从而改善…...
【推拉框-手风琴】vue3实现手风琴效果的组件
简言 在工作时有时会用到竖形手风琴效果的组件。 在此记录下实现代码和实现思路。 手风琴实现 结构搭建 搭建结构主要实现盒子间的排列效果。 用flex布局或者其他布局方式将内容在一行排列把每一项的内容和项头用盒子包裹, 内容就是这一项要展示的内容…...
滑动窗口最大值:单调队列
239. 滑动窗口最大值 难度困难2154收藏分享切换为英文接收动态反馈 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例…...
负载均衡算法
静态负载均衡 轮询 将请求按顺序轮流地分配到每个节点上,不关心每个节点实际的连接数和当前的系统负载。 优点:简单高效,易于水平扩展,每个节点满足字面意义上的均衡; 缺点:没有考虑机器的性能问题&…...
C语言数组二维数组
C 语言支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。 数组的声明并不是声明一个个单独的变量,比如 runoob0、runoob1、…、runoob99,而是…...
7年测试工程师,裸辞掉17K的工作,想跳槽找更好的,还是太高估自己了....
14年大学毕业后,在老师和朋友的推荐下,进了软件测试行业,这一干就是7年时间,当时大学本来就是计算机专业,虽然专业学的一塌糊涂,但是当年的软件测试属于新兴行业,人才缺口比较大,而且…...
企业为什么需要做APP安全评估?
近几年新型信息基础设施建设和移动互联网技术的不断发展,移动APP数量也呈现爆发式增长,进而APP自身的“脆弱性”也日益彰显,这对移动用户的个人信息及财产安全带来巨大威胁和挑战。在此背景下,国家出台了多部法律法规,…...
重回利润增长,涪陵榨菜为何能跑赢周期?
2022年消费市场持续低迷,疫情寒冬之下,不少食品快消企业均遭遇严重的业绩下滑,但一年里不断遭遇利空打击的“榨菜茅”涪陵榨菜,不仅安然躲过“酸菜劫”、走出“钠”争议,而且顺利将产品价格提起来,并在寒冬…...
这6个高清图片素材库,马住,马住~
网上找的图片素材清晰度不够,版权不明确怎么办。看看这几个可商用图片素材网站,解决你的所有图片需求,高清无水印,赶紧马住! 1、菜鸟图库 美女图片|手机壁纸|风景图片大全|高清图片素材下载网 - 菜鸟图库 网站素材…...
绝对零基础的C语言科班作业(期末模拟考试)
编程题(共10题; 共100.0分)模拟1(输出m到n的素数)从键盘输入两个整数[m,n], 输出m和n之间的所有素数。 输入样例:3,20输出样例:3 5 7 11 13 17 19 (输出数据之间用空格间…...
注解开发定义bean
注解开发定义bean 使用Component定义bean在核心配置文件中通过组件扫描加载bean,需要指定扫描包的范围 当然也可以使用Component的衍生注解,可以更加形象的表示 纯注解的开发模式 使用java类来代替了以前的 配置文件,在java类中ÿ…...
剑指 Offer 19. 正则表达式匹配
摘要 剑指 Offer 19. 正则表达式匹配 请实现一个函数用来匹配包含. 和*的正则表达式。模式中的字符.表示任意一个字符,而*表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如&#x…...
CSS——学成在线案例
🍓个人主页:bit.. 🍒系列专栏:Linux(Ubuntu)入门必看 C语言刷题 数据结构与算法 HTML和CSS3 目录 1.案例准备工作 2.CSS属性书写顺序(重点) 3.页面布局整体思路 4.头部的制作编辑 5.banner制作…...
元数据的类型
元数据通常分为三种类型:业务元数据、技术元数据和操作元数据。这些类别使人们能够理解属于元数据总体框架下的信息范围,以及元数据的产生过程。也就是说,这些类别也可能导致混淆,特别是当人们对一组元数据属于哪个类别或应该由谁…...
LEAP模型的能源环境发展、碳排放建模预测及不确定性分析
LEAP(Long Range Energy Alternatives Planning System/ Low emission analysis platform,长期能源可替代规划模型)是一种自下而上的能源-环境核算工具,由斯德哥尔摩环境研究所和美国波士顿大学联合研发。该模型与情景分析法紧密结…...
C# Task详解
1、Task产生背景 Task出现之前,微软的多线程处理方式有:Thread→ThreadPool→委托的异步调用,虽然也可以基本业务需要的多线程场景,但它们在多个线程的等待处理方面、资源占用方面、线程延续和阻塞方面、线程的取消方面等都显得比…...
个人备案网站做商业/营销策略都有哪些
最近在工作中遇到一个非常奇怪的问题,在两台主主同步的mysql数据库中,经常出现修改表结构后,两个库中结构不一致的情况,查看同步状态,木有任何报错,数据可正常同步,我自己在操作数据库进行索引创…...
源码做网站教程/百度推广优化技巧
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼最近学习CUDA C的编程,在并行运行一个简单的解调算法的时候,统计时间后发现运行速度越来越慢(但还是运算结果正确的),后来简化到只运行其中一个核函数的时候,就算复杂度下降了&#x…...
wordpress批量增加用户/北京百度推广代理
这几天在修改canal, 连接mysql和maria接收到的event有所区别 拿一个简单的insert sql来举例 mysql 会有以下几个event写入到binlog里 1.ANONYMOUS_GTID_LOG_EVENT2.QUERY_EVENTheader { version: 1 logfileName: "20170105-162017-bin.000001" logfileOffset: 192…...
windows 做网站服务器/百度关键词优化是什么意思
%>_<% 今天不是一般的被虐啊!!! 先是高高兴兴的在发展中学校A了一题,发现没人做,过来HDU就悲剧了…… Bonsai Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S…...
宁夏一站式网站建设/自己建网站的详细步骤
历史文章《国内最全的Spring Boot系列之一》《国内最全的Spring Boot系列之二》马上要过年了,作者要回家好好休息一下了,吃饱喝足,明年继续。在此和大家拜个早年,祝大家:鼠年大吉、心想事成、万事如意、开心每一天。「…...
2017还有人做网站吗/百度24小时人工电话
在命令行下运行 msdtc -uninstall ,卸载 msdtc 服务; 再运行 msdtc -install ,安装 msdtc 服务转载于:https://www.cnblogs.com/wlwjc/articles/1690230.html...