上一期,讲到了关于线程死锁、用户进程、用户线程的相关知识,不记得的小伙伴可以看看:字节跳动面试官问我:你知道线程死锁吗?用户线程、守护线程的概念与区别了解吗? 这期,我们来聊一聊一个在Java并发编程中很重要的类:ThreadLocal 在多线程应用程序中,对共享变量进行读写的场景是很常见的。如果不使用一定的技术或方案,会引发各种线程安全的问题。常见解决线程安全的方式有synchronized、volatile等方式,但synchronized对性能的开销大,volatile不能保证原子性,所以这里介绍一个 解决多线程间共享变量的线程安全问题 的方法——ThreadLocal
一、ThreadLocal的作用
多线程访问同一个共享变量时特别容易出现并发问题,特别是在多个线程需要对共享变量进行写入时。为了保证线程安全,一般使用者在访问共享变量时需要进行适当的同步,如图 1-3 所示 同步的措施一般是加锁,但加锁会在一定程度上增加系统的复杂度以及影响系统的性能。
为了解决多线程间共享变量的线程安全,ThreadLocal应运而生。
当创建一个ThreadLocal变量时,访问这个变量的每个线程都有这个变量的一个本地副本,当多个线程操作这个变量时,实际上就是操作自己本地内存里面的变量,从而避免了线程安全问题。图 1-3 就变成了 图1-4 如图:
二、Threadlocal的使用示例
讲完了理论的东西,我们来通过下面的例子体会下ThreadLocal的神奇之处吧
public class ThreadLocalTest {
private static ThreadLocal threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
threadLocal.set("本地变量1");
print("thread1");
System.out.println("线程1的本地变量的值为:"+threadLocal.get());
});
Thread thread2 = new Thread(() -> {
threadLocal.set("本地变量2");
print("thread2");
System.out.println("线程2的本地变量的值为:"+threadLocal.get());
});
thread1.start();
thread2.start();
}
public static void print(String s){
System.out.println(s+":"+threadLocal.get());
}
}
执行结果如下: 上述代码中,有一个 threadLocal 变量,类型为ThreadLocal ,然后创建了 thread1 和 thread2 ,并分别在两个线程中调用了 threadLocal.set(String str) 方法,然后用 threadLocal.get() 方法去获取threadLocal变量的值。显然,由输出结果可以知道,线程 thread1 中获取到的值就是它给threadLocal设置的值,即为本地变量1;线程 thread2 中获取到的值就是它给threadLocal设置的值,即为本地变量2。这两个线程是访问不到另外一个线程中的threadLocal的值的。
应用讲完了,现在着重来看一下ThreadLocal的实现原理(大厂面试必问~)
1、ThreadLocal 的 set、get方法
首先看下ThreadLocal 相关类的类图结构:
再看一下Thraed里面的成员变量
我们可以发现Thread类中有两个类型为ThreadLocalMap的变量,ThreadLoaclMap是一个定制化的HashMap。
在默认情况下,每个线程中的这两个变量都为null:
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
只有当线程第一次调用ThreadLocal的set方法或get方法时才会创建它们。
public void set(T value) {
//(1)获取当前线程
Thread t = Thread.currentThread();
//(2)将当前线程作为key,去查找对应的线程变量,找到则设置。
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//(3)第一次调用set方法时,就创建当前线程对应的HashMap。
createMap(t, value);
}
(1)处代码首先获取调用set方法的线程,然后使用当前线程作为参数调用getMap(t)
方法,getMap(Thread t)
方法如下:
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
可以看到,getMap(t)
的作用是获取线程自己的变量 threadLocals ,其类型是ThreadLocalMap 。
如果getMap(t)
的返回值非空,则把value值存放到threadLocals中,即把当前变量值存放入当前线程的成员变量threadLocals中。
threadLocals是一个HashMap结构,其中key就是当前ThreadLocal的实例对象引用,value是通过set方法传递的值。
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
如果getMap(t)
返回的是null,则说明是第一次调 set
方法,这时创建 当前线程的threadLocals 变量。 下面来看 createMap(t, value)
干了啥:
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
即创建了一个ThreadLocalMap对象,并将当前线程的threadLocals引用执行它。
再来看看get()方法的代码实现
public T get() {
//(4)获取当前线程
Thread t = Thread.currentThread();
//(5)获取当前线程的threadLocals变量
ThreadLocalMap map = getMap(t);
//(6)如果threadLocals不为null,则返回对应的本地变量的值
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//(7)threadLocals为空时,则初始化当前线程的threadLocals成员变量
return setInitialValue();
}
(4)处的代码首先获取当前线程实例,如果当前线程的threadLocals不为null,则直接返回当前线程绑定的本地变量;否则执行(7)处代码进行初始化。setInitialValue()
方法如下:
private T setInitialValue() {
//(8)初始化为null
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
//(9)如果当前线程的threadLocals变量不为空
if (map != null)
map.set(this, value);
else
//(10)为空则创建一个ThreadLocalMap对象,并将当前线程的threadLocals引用执行它。
createMap(t, value);
return value;
}
如果当前线程的threadLocals变量不为空,则设置当前线程的本地变量值为null;否则调用createMap方法创建ThreadLocalMap对象,并将当前线程的threadLocals引用执行它。
总结下:在每个线程里都有 threadLocals 的成员变量,该变量的类型为ThreadLocalMap(实际上可以理解为定制的HashMap),其中key为我们所定义的ThreadLocal变量的this引用,value则为set方法传递的值。每个线程的本地变量存放在线程自己的成员变量threadLocals中,如果当前线程一直不消亡,那么这些本地变量会一直存在,故可能会造成内存溢出,故使用完毕后需要使用 remove() 方法删除threadLocals中的本地变量 。
2、Threadlocal 不支持继承性
首先看下下面代码:
public class TestThreadLocal {
//(1)创建线程变量
public static ThreadLocal threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
//(2)赋值本地变量
threadLocal.set("hello world");
//(3)启动子线程
new Thread(() -> {
//(4)子线程输出线程变量的值
System.out.println("thread:" + threadLocal.get());
}).start();
//(5)主线程输出线程变量的值
System.out.println("main:" + threadLocal.get());
}
}
输出结果如下:
输出结果说明:同一个 ThreadLocal 变量在父线程中被设置值后,在子线程中是获取不到的。 原因是:子线程里面调用get方法时,Thread t = Thread.currentThread()
代码是获取当前线程,当前线程是子线程,而调用set方法给threadLocal赋值的线程是main,两者是不同的线程,故子线程调用get方法取得的threadLocal值为null,main线程调用get方法取得的threadLocal值为“hello world”。
有没有方法让子线程能够访问到父线程中的值?继续往下看啦。
3、lnheritableThreadLocal 类
为了解决让子线程能够访问到父线程中的值 的问题,lnheritableThreadLocal 应运而生。lnheritableThreadLocal 继承自 ThreadLocal,并提供了一个新特性:让子线程可以访问在父线程中设置的本地变量值。先来看下lnheritableThreadLocal 的实现:
public class InheritableThreadLocal extends ThreadLocal {
//(1)
protected T childValue(T parentValue) {
return parentValue;
}
//(2)
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
//(3)
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
}
通过查看 InheritableThreadLocal 的源码可知,lnheritableThreadLocal 继承了 ThreadLocal 类并重新了 childValue、getMap、createMap方法。
由(3)处代码可知,InheritableThreadLocal 重写了 createMap
方法,那么当第一次调用 InheritableThreadLocal 实例的set方法时,创建的就是当前线程的inheritableThreadLocals变量的实例而不再是threadLocals了。
由(2)处代码可知,InheritableThreadLocal 重写了 getMap
方法,那么调用InheritableThreadLocal 实例的get方法时,就是获取当前线程的inheritableThreadLocals变量的实例而不再是threadLocals。
那么(1)处代码是如何实现子线程可以访问在父线程中设置的本地变量值的?
这要从创建Thread的代码将起,打开Thread类的默认构造函数:
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
......
//(4)获取当前线程
Thread parent = currentThread();
......
//(5)如果父线程的inheritableThreadLocals 变量不为null
if (parent.inheritableThreadLocals != null)
//(6)设置子线程中的 inheritableThreadLocals 变量
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
......
}
由(4)处代码,获取了当前线程(main函数所在的线程,即父线程)
这里可能有同学会有疑问,这里获取到的当前线程为何是父线程? 想一下,当我们new Thread()的时候,是不是在main()方法里执行的,所以当前执行创建Thread代码的线程是main线程,所以(4)处代码中currentThread()方法获取到的就是父线程啦!
由(5)处代码,判断main线程里的inheritableThreadLocals 是否为null,不为null时,则执行代码(6)。
由(6)处代码,我们来看看createInheritedMap()
方法:
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}
在createInheritedMap
方法中,使用父线程的inheritableThreadLocals变量作为构造函数创建了一个新的ThreadLocalMap对象,由(6)处:this.inheritableThreadLocals=ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
知道将子线程的inheritableThreadLocals引用指向了这个新创建的ThreadLocalMap对象。
再看看 ThreadLocalMap(parentMap)
构造函数:
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
table = new Entry[len];
for (int j = 0; j < len; j++) {
Entry e = parentTable[j];
if (e != null) {
@SuppressWarnings("unchecked")
ThreadLocal key = (ThreadLocal) e.get();
if (key != null) {
//(7)调用了InheritableThreadLocal类重写的 childValue 方法
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
int h = key.threadLocalHashCode & (len - 1);
while (table[h] != null)
h = nextIndex(h, len);
table[h] = c;
size++;
}
}
}
}
在构造函数中就是把父线程的inheritableThreadLocal变量的值复制到新的ThreadLocalMap对象中,(7)处代码实际上是调用了(1)处代码。
总结一下:InheritableThreadLocal实现子线程可以访问父线程的线程变量的实现原理如下:
InheritableThreadLocal通过重写createMap
和 getMap
方法让本地变量保存到了具体线程的inheritableThreadLocal变量中
线程通过调用inheritableThreadLocal实例的set
或get
方法时,就会创建当前线程的inheritableThreadLocal变量
当父线程创建子线程时,构造函数会把父线程中的inheritableThreadLocal变量里面的本地变量值复制一份保存到子线程的inheritableThreadLocal变量里
将最开始的代码作以下修改:
public class TestThreadLocal {
//(1)创建线程变量
public static InheritableThreadLocal threadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
//(2)赋值本地变量
threadLocal.set("hello world");
//(3)启动子线程
new Thread(() -> {
//(4)子线程输出线程变量的值
System.out.println("thread:" + threadLocal.get());
}).start();
//(5)主线程输出线程变量的值
System.out.println("main:" + threadLocal.get());
}
}
结果就变成了:
很多子线程需要使用父线程中的变量值的场景都可以使用InheritableThreadLocal,是不是很强大呢?
这期就到这里,ThreadLocal、InheritableThreadLocal在Java并发编程中的地位举足轻重,理解了它们的底层实现和应用场景,会让你的大厂面试更有加分项。你们的三连是我创作的最大动力 ,我们下期见。
你可能感兴趣的:(多线程)
老榕树的Java专题:深入理解线程池
程序员_老榕树
树哥java专题:从0到1 java jvm
一、引言在现代软件开发中,多线程编程是提升应用程序性能与响应性的关键手段。不过,频繁创建和销毁线程会产生较大开销,线程池技术便由此诞生。它能高效管理线程,提高线程复用性,进而增强系统整体性能。本文将深入探究线程池的概念、原理、优势,以及在Java中的具体应用。二、线程池的概念线程池,简言之,就是容纳多个线程的“池子”。系统启动时,它会预先创建一定数量的线程,并将其存储在一个线程队列中。当有任务需要
Java 实例 - 死锁及解决方法
William Dawson
java 开发语言
死锁(Deadlock)是多线程编程中的一种常见问题,指的是两个或多个线程在执行过程中,因为争夺资源而造成的一种互相等待的现象,导致这些线程都无法继续执行下去。死锁通常发生在多个线程需要同时获取多个锁的情况下。死锁产生的四个必要条件:互斥条件:资源一次只能被一个线程占用。占有并等待:线程持有至少一个资源,并等待获取其他被占用的资源。非抢占条件:线程已持有的资源不能被其他线程强行抢占,只能由线程自己
多线程-CompletableFuture
侧耳倾听111
java
简介CompletableFuture:异步任务编排工具。java8中引入的一个类,位于juc包下,是Future的增强版。它可以让用户更好地构建和组合异步任务,避免回调地狱。在CompletableFuture中,如果用户没有指定执行异步任务时的线程池,默认使用ForkJoinPool中的公共线程池。使用案例简单使用几个入门案例,学习如何使用CompletableFuture提交异步任务并行接收
多线程-线程池源码
侧耳倾听111
java
简介这里了解ThreadPoolExecutor的工作机制ThreadPoolExecutor的继承结构Executor:线程池的顶层接口,定义了提交异步任务的方法voidexecute(Runnablecommand);ExecutorService:继承Executor,定义了关闭线程池、查看线程池是否关闭、提交有返回值的异步任务、批量提交异步任务的功能publicinterfaceExecu
多线程设计模式-本地线程(Threadlocal)使用详解以及原理介绍
睡醒的土豆
java多线程 java并发编程 多线程设计模式 多线程 并发编程 thread
本地线程(Threadlocal)什么是ThreadLocal变量ThreadLoal变量,线程局部变量,同一个ThreadLocal所包含的对象,在不同的Thread中有不同的副本。这里有几点需要注意:因为每个Thread内有自己的实例副本,且该副本只能由当前Thread使用。这是也是ThreadLocal命名的由来。既然每个Thread有自己的实例副本,且其它Thread不可访问,那就不存在多
FFMpeg av_packet_ref 引起软件crash问题
ihmhm12345
ffmpeg
av_packet_ref引起软件crash问题ffmpeg在多线程编程中,相信大家必然会用到av_packet_ref来解决大量复制内存的问题,这里有个坑,多线程中,每个线程应该去管理自己的AVPacket,不要跨线程管理/释放AVPacket…如果有遇到类似问题的,希望能解决大家的疑惑我项目中的做法:解封装线程取出AVPacket发送到解码线程同时也发送到录像线程我之前的做法是解码线程使用解封
Qt:多线程
cfqcfqcfqcfqcfq
Qt
UI程序经常会遇到的一个问题是在执行一个长时间任务时,UI线程被阻塞,导致假面出现假死现象,之前文章也有介绍解决办法(比如使用一个进度对话框)。今天主要是通过开启一个线程方式来解决UI线程阻塞问题。想要使用线程就需要对Qt多线程编程有一个了解。在Qt中使用多线程需要用到QThread类QTHread类为用户管理多线程提供了一种平台无关的途径#include继承自QObject类在Qt帮助文档里为我
Qt:多线程中断
cfqcfqcfqcfqcfq
Qt
线程使用有两种方法,具体介绍见:http://blog.csdn.net/cfqcfqcfqcfqcfq/article/details/51627885;;关于线程中断的函数:quit()Exit()terminate();除此之外比较常用的函数(起到阻塞作用):wait()sleep();在线程类被析构的时候,应该习惯性的设置中断和阻塞;避免出现一些不必要的错误;分别在两种线程使用方法中说明这
【前端进阶】Web Worker性能优化实战:解码10万条数据不卡顿
爱上大树的小猪
前端 性能优化
为什么需要WebWorker?JavaScript是单线程语言,当处理大量数据(如解析10万条JSON数据)时,主线程会被阻塞,导致页面卡顿、无法响应点击事件。WebWorker是浏览器提供的多线程解决方案,可以将耗时任务放到后台执行,解放主线程!实战目标主线程流畅渲染,10万条数据解码不卡顿!代码案例与分步解析1.模拟10万条数据//生成10万条模拟数据functiongenerateMockD
SHEIN面试——Java高级开发
有鹿如溪
面试 Java 面试 职场和发展
2022年7月20希音二面高级开发工程师(供应链)面试流程1自我介绍2问问题开始多线程:1线程间的通信方式2什么是pua定义3什么是内卷的定义4spring和mybatis怎么操作数据库的5平时工作量怎么定义的6工作技巧7如何提升工作效率8对加班有啥看法9为啥离职耗时:30分钟
Android中的AtomicLong:原理、使用与实战指南
jiet_h
Android 夯实基础 android
本文结合生产环境实战案例,带你彻底搞懂AtomicLong在Android多线程开发中的应用。全文包含大量Kotlin代码示例,建议收藏备用。一、为什么需要AtomicLong?在Android开发中,当多个线程同时操作同一个Long型变量时,你可能会遇到这样的诡异场景:varcounter=0Lfunincrement(){//这个操作在并发场景下会出错!counter++}这个简单的自增操作,
java面试问题大全及答案大全
小白教程
java面试题 java 面试 开发语言 java面试题 java面试问题大全 java面试题带答案 Java经典面试题
文章目录前言java面试题-Java基础java面试题-JVM知识java面试题-多线程与并发java面试题-主流框架java面试题-数据库相关java面试题-分布式与微服务java面试题-网络知识前言该文档围绕Java技术栈展开,全面涵盖了基础、JVM、多线程与并发、主流框架、数据库、分布式、网络等核心知识领域,以面试题及参考答案的形式呈现,为Java开发者提供了系统复习与深入理解的资料。有需要
C/C++ 面试大纲
八月的雨季997
C++ / C++11 c++
文章目录C程序运行数组指针字符串内存模型内存对齐内存泄露内存拷贝链表文件排序快排选择冒泡折半C++封装继承多态类型转化:默认构造继承方式构造顺序虚继承多态:虚析构函数虚构造C++11lambdafunctor移动构造智能指针:多线程STLvectorlistsetmultiset哈希表unorderd_setmapmultimapunorderd_map仿函数算法设计模式设计原则:单例模式单例模式
Java多线程与高并发专题——为什么 Map 桶中超过 8 个才转为红黑树?
黄雪超
技术基础 java 开发语言 并发编程
引入JDK1.8的HashMap和ConcurrentHashMap都有这样一个特点:最开始的Map是空的,因为里面没有任何元素,往里放元素时会计算hash值,计算之后,第1个value会首先占用一个桶(也称为槽点)位置,后续如果经过计算发现需要落到同一个桶中,那么便会使用链表的形式往后延长,俗称“拉链法”。当链表长度大于或等于阈值(默认为8)的时候,如果同时还满足容量大于或等于MIN_TREEI
10、Java核心API系列(八)
跟着汪老师学编程
java 开发语言
九、并发与多线程1、Java并发API概述Java并发API是Java语言中用于多线程编程的核心工具包,主要位于java.util.concurrent和java.util.concurrent.locks包中。它提供了高效、简洁的方式来处理并发编程中的常见问题。Java并发的核心目标:提高程序的响应速度。提高程序的吞吐量(处理更多任务)。-简化并发编程的复杂性。Java并发的基本概念:线程(Th
为什么不直接创建线程,自定义线程池需要指定哪些参数,重要性如何?
重生之我在成电转码
java jvm 开发语言 八股
为什么不直接创建线程,而要用线程池?直接创建线程的问题:性能开销大:每次创建新线程都有内存分配、上下文切换等开销,频繁创建销毁会导致性能下降。资源耗尽风险:线程数量不受控,可能导致内存溢出(OutOfMemoryError)或CPU过载。缺乏管理:线程生命周期不可控,难以统一管理。上下文切换频繁:过多线程会导致CPU在线程间频繁切换,反而降低性能。无法复用:直接创建的线程执行完毕后销毁,无法重复使
.NET 多线程 C# 多线程 持续更新、完善、进化
shepherd枸杞泡茶
C# .net c#
在.NET环境下,多线程编程主要有ThreadThreadPoolTaskParallelBackgroundWorker等几种,还有一个与多线程相关的:异步编程async/await,值得强调的是,异步编程不等于多线程。当然,这几种多线程编程的方式并不是独立开的,在底层的封装有一定的联系。1.Thread1.1基础应用引用Thread的命名空间usingSystem;usingSystem.Th
手把手教你理解IO多路复用
做自己'S Catanin
数据库 java sql
一、为什么需要IO多路复用?想象一个餐厅服务员的故事:传统阻塞模式:服务员每次只服务一桌客人,其他客人必须等待多线程模式:给每桌都配一个专属服务员(资源消耗大)IO多路复用:一个服务员同时监听多桌需求,谁好了处理谁这就是IO多路复用的核心价值——用单线程/进程管理多个IO流!二、select系统调用详解2.1select工作原理intselect(intnfds,fd_set*readfds,fd
《基于WebGPU的下一代科学可视化——告别WebGL性能桎梏》
Eqwaak00
matplotlib webgl 微服务 架构 云原生 分布式
引言:科学可视化的算力革命当WebGL在2011年首次亮相时,它开启了浏览器端3D渲染的新纪元。然而面对当今十亿级粒子模拟、实时物理仿真和深度学习可视化需求,WebGL的架构瓶颈日益凸显。WebGPU作为下一代Web图形标准,通过显存直存、多线程渲染和计算着色器三大革新,将科学可视化性能提升至10倍以上。本文将深入解析如何利用WebGPU突破大规模数据渲染的极限。一、WebGPU核心架构解析1.1
JavaAdv——多线程同步案例(售票系统)
搬码红绿灯
java
售票系统假设您正在开发一个基于Java多线程技术的售票系统。该系统需要支持多个售票窗口同时进行售票操作,并且要确保不会出现超卖或漏卖的情况。具体来说,系统应该具备如下特点:票的数量有限:初始时系统中有100张票。多线程售票:系统支持多个售票窗口同时进行售票操作。线程安全:必须确保即使在高并发情况下也不会出现超卖或漏卖的问题。Runnable==查看结果,分析代码==publicvoidrun(){
Python爬取亚马逊商品数据-多线程【附源码】
代码CC
python爬虫 python 爬虫 多线程 开发语言
效果如下图:代码用途说明(完整代码在后面)核心功能本代码用于自动化采集亚马逊平台商品数据,主要获取以下信息:商品分类:通过URL参数自动识别商品类别(如electronics/beauty)商品名称:精准提取商品标题用户评分:解析星级评分(4.5/5.0等)销售信息:获取近期销售数据应用场景市场调研:分析不同商品类别的市场竞争情况价格监控:跟踪商品价格波动趋势竞品分析:获取同类商品的用户评价数据库
TiDB系列之:使用Flink TiDB CDC Connector采集数据
快乐骑行^_^
日常分享专栏 TiDB系列 使用Flink TiDB CDC Connector采集数据
TiDB系列之:使用FlinkTiDBCDCConnector采集数据一、依赖项二、Maven依赖三、SQLClientJAR四、如何创建TiDBCDC表五、连接器选项六、可用元数据七、特征一次性处理启动阅读位置多线程读取DataStreamSource八、数据类型映射TiDBCDC连接器允许从TiDB数据库读取快照数据和增量数据。本文档介绍如何设置TiDBCDC连接器以对TiDB数据库运行SQL
新闻推荐系统:Spring Boot框架详解
2402_85758936
spring boot 后端 java
2相关技术2.1MYSQL数据库MySQL是一个真正的多用户、多线程SQL数据库服务器。是基于SQL的客户/服务器模式的关系数据库管理系统,它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等,非常适用于Web站点或者其他应用软件的数据库后端的开发工作。此外,用户可利用许多语言编写访问MySQL数据库的程序。作为开放源代码运动的产物之一,MyS
Java多线程,线程安全,线程死锁,线程通信,线程同步(上)
Alie鱼
Java高级 java 多线程 线程安全
什么是线程??线程是计算机执行的最小单位,在一个进程中可以有多个不同线程多线程有什么用?干什么的?单线程就像一个瓶子戳一个洞,而多线程是戳了多个洞,可以提高程序的执行效率,一个事情分配到不同线程同时执行,在写的程序往往会遇到同时处理多个问题的情况,而单线程必须上一个任务完成后才能执行下一个任务无法完成同时处理多个任务的情况,而多线程就是来解决这个问题的,不用等待上一个任务结束,提高了程序的响应度和
Python进阶--多线程
桔子code
Python笔记本 多线程 python
原文链接:http://www.juzicode.com/archives/841在《Python进阶教程m9–网络通信–socket通信》中我们实现了一个socket服务端和客户端通信的例子,这个例子中服务端需要等待客户端发送消息后才能返回消息给客户端,在客户端没有发送消息时,服务端一直在data=connet.recv(1024)上被阻塞住,直到等到客户端发来消息才能做下一步的动作。但是在实际
python 进程池pool使用详解
北冥有鱼喵喵
python学习 python
和选用线程池来关系多线程类似,当程序中设置到多进程编程时,Python提供了更好的管理多个进程的方式,就是使用进程池。在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态生成多个进程,十几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又
ThreadLocal的使用与原理解析
Rolland_hero
JUC学习以及源码分析 juc
目录基本介绍使用方法实际案例ThreadLocal的实现原理结构介绍ThreadLocal的核心方法源码set方法get方法remove方法ThreadLocal的内存泄露问题ThreadLocalMap扩容问题基本介绍从Java官方文档中的描述:ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的
ThreadLocal解析
八股文领域大手子
数据库 java sql jvm
1.ThreadLocal的定义与核心作用ThreadLocal是Java中用于实现线程局部变量的工具类。它为每个线程提供独立的变量副本,使得每个线程访问的是自己的数据,从而避免多线程环境下的资源共享问题,实现线程隔离。例如,解决SimpleDateFormat的非线程安全问题:每个线程通过ThreadLocal持有自己的实例,避免并发修改。2.使用场景线程安全资源管理:如数据库连接(Connec
RV1126的OSD模块和SDL_TTF结合输出H264文件
weixin_51931174
ffmpeg
目录一.RV1126多线程处理输出OSD字符叠加图层的流程1.1.VI模块的初始化1.2.初始化VENC模块:1.3.初始化RGN模块:1.4.绑定VI模块和VENC模块,伪代码如下1.5.创建多线程进行OSD字库的叠加:1.6.获取每一帧处理过后的VENC数据:二.程序代码三.运行结果一.RV1126多线程处理输出OSD字符叠加图层的流程用RV1126多线程输出OSD叠加需要经过上面几个重要步骤
通过多线程获取RV1126的AAC码流
weixin_51931174
linux
目录一RV1126多线程获取音频编码AAC码流的流程1.1AI模块的初始化并使能1.2AENC模块的初始化1.3绑定AI模块和AENC模块1.4多线程获取每一帧AAC码流1.5每个AAC码流添加ADTSHeader头部1.6写入具体每一帧AAC的ES码流二代码实战一RV1126多线程获取音频编码AAC码流的流程上面是RV1126多线程获取AAC码流的流程,分为六步:AI模块的初始化并使能、AENC
统一思想认识
永夜-极光
思想
1.统一思想认识的基础,才能有的放矢
原因:
总有一种描述事物的方式最贴近本质,最容易让人理解.
如何让教育更轻松,在于找到最适合学生的方式.
难点在于,如何模拟对方的思维基础选择合适的方式. &
Joda Time使用笔记
bylijinnan
java joda time
Joda Time的介绍可以参考这篇文章:
http://www.ibm.com/developerworks/cn/java/j-jodatime.html
工作中也常常用到Joda Time,为了避免每次使用都查API,记录一下常用的用法:
/**
* DateTime变化(增减)
*/
@Tes
FileUtils API
eksliang
FileUtils FileUtils API
转载请出自出处:http://eksliang.iteye.com/blog/2217374 一、概述
这是一个Java操作文件的常用库,是Apache对java的IO包的封装,这里面有两个非常核心的类FilenameUtils跟FileUtils,其中FilenameUtils是对文件名操作的封装;FileUtils是文件封装,开发中对文件的操作,几乎都可以在这个框架里面找到。 非常的好用。
各种新兴技术
不懂事的小屁孩
技术
1:gradle Gradle 是以 Groovy 语言为基础,面向Java应用为主。基于DSL(领域特定语言)语法的自动化构建工具。
现在构建系统常用到maven工具,现在有更容易上手的gradle,
搭建java环境:
http://www.ibm.com/developerworks/cn/opensource/os-cn-gradle/
搭建android环境:
http://m
tomcat6的https双向认证
酷的飞上天空
tomcat6
1.生成服务器端证书
keytool -genkey -keyalg RSA -dname "cn=localhost,ou=sango,o=none,l=china,st=beijing,c=cn" -alias server -keypass password -keystore server.jks -storepass password -validity 36
托管虚拟桌面市场势不可挡
蓝儿唯美
用户还需要冗余的数据中心,dinCloud的高级副总裁兼首席营销官Ali Din指出。该公司转售一个MSP可以让用户登录并管理和提供服务的用于DaaS的云自动化控制台,提供服务或者MSP也可以自己来控制。
在某些情况下,MSP会在dinCloud的云服务上进行服务分层,如监控和补丁管理。
MSP的利润空间将根据其参与的程度而有所不同,Din说。
“我们有一些合作伙伴负责将我们推荐给客户作为个
spring学习——xml文件的配置
a-john
spring
在Spring的学习中,对于其xml文件的配置是必不可少的。在Spring的多种装配Bean的方式中,采用XML配置也是最常见的。以下是一个简单的XML配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.or
HDU 4342 History repeat itself 模拟
aijuans
模拟
来源:http://acm.hdu.edu.cn/showproblem.php?pid=4342
题意:首先让求第几个非平方数,然后求从1到该数之间的每个sqrt(i)的下取整的和。
思路:一个简单的模拟题目,但是由于数据范围大,需要用__int64。我们可以首先把平方数筛选出来,假如让求第n个非平方数的话,看n前面有多少个平方数,假设有x个,则第n个非平方数就是n+x。注意两种特殊情况,即
java中最常用jar包的用途
asia007
java
java中最常用jar包的用途
jar包用途axis.jarSOAP引擎包commons-discovery-0.2.jar用来发现、查找和实现可插入式接口,提供一些一般类实例化、单件的生命周期管理的常用方法.jaxrpc.jarAxis运行所需要的组件包saaj.jar创建到端点的点到点连接的方法、创建并处理SOAP消息和附件的方法,以及接收和处理SOAP错误的方法. w
ajax获取Struts框架中的json编码异常和Struts中的主控制器异常的解决办法
百合不是茶
js json编码返回异常
一:ajax获取自定义Struts框架中的json编码 出现以下 问题:
1,强制flush输出 json编码打印在首页
2, 不强制flush js会解析json 打印出来的是错误的jsp页面 却没有跳转到错误页面
3, ajax中的dataType的json 改为text 会
JUnit使用的设计模式
bijian1013
java 设计模式 JUnit
JUnit源代码涉及使用了大量设计模式
1、模板方法模式(Template Method)
定义一个操作中的算法骨架,而将一些步骤延伸到子类中去,使得子类可以不改变一个算法的结构,即可重新定义该算法的某些特定步骤。这里需要复用的是算法的结构,也就是步骤,而步骤的实现可以在子类中完成。
Linux常用命令(摘录)
sunjing
crond chkconfig
chkconfig --list 查看linux所有服务
chkconfig --add servicename 添加linux服务
netstat -apn | grep 8080 查看端口占用
env 查看所有环境变量
echo $JAVA_HOME 查看JAVA_HOME环境变量
安装编译器
yum install -y gcc
【Hadoop一】Hadoop伪集群环境搭建
bit1129
hadoop
结合网上多份文档,不断反复的修正hadoop启动和运行过程中出现的问题,终于把Hadoop2.5.2伪分布式安装起来,跑通了wordcount例子。Hadoop的安装复杂性的体现之一是,Hadoop的安装文档非常多,但是能一个文档走下来的少之又少,尤其是Hadoop不同版本的配置差异非常的大。Hadoop2.5.2于前两天发布,但是它的配置跟2.5.0,2.5.1没有分别。 &nb
Anychart图表系列五之事件监听
白糖_
chart
创建图表事件监听非常简单:首先是通过addEventListener('监听类型',js监听方法)添加事件监听,然后在js监听方法中定义具体监听逻辑。
以钻取操作为例,当用户点击图表某一个point的时候弹出point的name和value,代码如下:
<script>
//创建AnyChart
var chart = new AnyChart();
//添加钻取操作&quo
Web前端相关段子
braveCS
web前端
Web标准:结构、样式和行为分离
使用语义化标签
0)标签的语义:使用有良好语义的标签,能够很好地实现自我解释,方便搜索引擎理解网页结构,抓取重要内容。去样式后也会根据浏览器的默认样式很好的组织网页内容,具有很好的可读性,从而实现对特殊终端的兼容。
1)div和span是没有语义的:只是分别用作块级元素和行内元素的区域分隔符。当页面内标签无法满足设计需求时,才会适当添加div
编程之美-24点游戏
bylijinnan
编程之美
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
public class PointGame {
/**编程之美
主页面子页面传值总结
chengxuyuancsdn
总结
1、showModalDialog
returnValue是javascript中html的window对象的属性,目的是返回窗口值,当用window.showModalDialog函数打开一个IE的模式窗口时,用于返回窗口的值
主界面
var sonValue=window.showModalDialog("son.jsp");
子界面
window.retu
[网络与经济]互联网+的含义
comsci
互联网+
互联网+后面是一个人的名字 = 网络控制系统
互联网+你的名字 = 网络个人数据库
每日提示:如果人觉得不舒服,千万不要外出到处走动,就呆在床上,玩玩手游,更不能够去开车,现在交通状况不
oracle 创建视图 with check option
daizj
视图 view oralce
我们来看下面的例子:
create or replace view testview
as
select empno,ename from emp where ename like ‘M%’
with check option;
这里我们创建了一个视图,并使用了with check option来限制了视图。 然后我们来看一下视图包含的结果:
select * from testv
ToastPlugin插件在cordova3.3下使用
dibov
Cordova
自己开发的Todos应用,想实现“
再按一次返回键退出程序 ”的功能,采用网上的ToastPlugins插件,发现代码或文章基本都是老版本,运行问题比较多。折腾了好久才弄好。下面吧基于cordova3.3下的ToastPlugins相关代码共享。
ToastPlugin.java
package&nbs
C语言22个系统函数
dcj3sjt126com
c function
C语言系统函数一、数学函数下列函数存放在math.h头文件中Double floor(double num) 求出不大于num的最大数。Double fmod(x, y) 求整数x/y的余数。Double frexp(num, exp); double num; int *exp; 将num分为数字部分(尾数)x和 以2位的指数部分n,即num=x*2n,指数n存放在exp指向的变量中,返回x。D
开发一个类的流程
dcj3sjt126com
开发
本人近日根据自己的开发经验总结了一个类的开发流程。这个流程适用于单独开发的构件,并不适用于对一个项目中的系统对象开发。开发出的类可以存入私人类库,供以后复用。
以下是开发流程:
1. 明确类的功能,抽象出类的大概结构
2. 初步设想类的接口
3. 类名设计(驼峰式命名)
4. 属性设置(权限设置)
判断某些变量是否有必要作为成员属
java 并发
shuizhaosi888
java 并发
能够写出高伸缩性的并发是一门艺术
在JAVA SE5中新增了3个包
java.util.concurrent
java.util.concurrent.atomic
java.util.concurrent.locks
在java的内存模型中,类的实例字段、静态字段和构成数组的对象元素都会被多个线程所共享,局部变量与方法参数都是线程私有的,不会被共享。
Spring Security(11)——匿名认证
234390216
Spring Security ROLE_ANNOYMOUS 匿名
匿名认证
目录
1.1 配置
1.2 AuthenticationTrustResolver
对于匿名访问的用户,Spring Security支持为其建立一个匿名的AnonymousAuthenticat
NODEJS项目实践0.2[ express,ajax通信...]
逐行分析JS源代码
Ajax nodejs express
一、前言
通过上节学习,我们已经 ubuntu系统搭建了一个可以访问的nodejs系统,并做了nginx转发。本节原要做web端服务 及 mongodb的存取,但写着写着,web端就
在Struts2 的Action中怎样获取表单提交上来的多个checkbox的值
lhbthanks
java html struts checkbox
第一种方法:获取结果String类型
在 Action 中获得的是一个 String 型数据,每一个被选中的 checkbox 的 value 被拼接在一起,每个值之间以逗号隔开(,)。
所以在 Action 中定义一个跟 checkbox 的 name 同名的属性来接收这些被选中的 checkbox 的 value 即可。
以下是实现的代码:
前台 HTML 代码:
003.Kafka基本概念
nweiren
hadoop kafka
Kafka基本概念:Topic、Partition、Message、Producer、Broker、Consumer。 Topic: 消息源(Message)的分类。 Partition: Topic物理上的分组,一
Linux环境下安装JDK
roadrunners
jdk linux
1、准备工作
创建JDK的安装目录:
mkdir -p /usr/java/
下载JDK,找到适合自己系统的JDK版本进行下载:
http://www.oracle.com/technetwork/java/javase/downloads/index.html
把JDK安装包下载到/usr/java/目录,然后进行解压:
tar -zxvf jre-7
Linux忘记root密码的解决思路
tomcat_oracle
linux
1:使用同版本的linux启动系统,chroot到忘记密码的根分区passwd改密码 2:grub启动菜单中加入init=/bin/bash进入系统,不过这时挂载的是只读分区。根据系统的分区情况进一步判断. 3: grub启动菜单中加入 single以单用户进入系统. 4:用以上方法mount到根分区把/etc/passwd中的root密码去除 例如: ro
跨浏览器 HTML5 postMessage 方法以及 message 事件模拟实现
xueyou
jsonp jquery 框架 UI html5
postMessage 是 HTML5 新方法,它可以实现跨域窗口之间通讯。到目前为止,只有 IE8+, Firefox 3, Opera 9, Chrome 3和 Safari 4 支持,而本篇文章主要讲述 postMessage 方法与 message 事件跨浏览器实现。postMessage 方法 JSONP 技术不一样,前者是前端擅长跨域文档数据即时通讯,后者擅长针对跨域服务端数据通讯,p