一、ThreadLocal原理分析
1、概念
ThreadLocal类并不是用来解决多线程环境下的共享变量问题,而是用来提供线程内部的共享变量。在多线程环境 下,可以保证各个线程之间的变量互相隔离、相互独立。
2、核心原理
即:实际上是ThreadLocal的静态内部类ThreadLocalMap为每个Thread都维护了一个数组table,ThreadLocal确定了一个数组下标,而这个下标就是value存储的对应位置。
3、ThreadLocal和Synchronized的区别与联系
联系:
threadLocal和Synchronized都是为了解决多线程中相同变量的访问冲突问题。
区别:
- Synchronized是通过线程等待,牺牲时间来解决访问冲突
- ThreadLocal是通过每个线程单独一份存储空间,牺牲空间来解决冲突,并且相比于Synchronized,ThreadLocal具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问到想要的值。
4、内存泄露问题
Entry类继承了WeakReference,即每个Entry对象都有一个ThreadLocal的弱引用,GC对于弱引用的对象采取积极的内存回收策略,避免无人搭理时发生内存泄露。
ThreadLocal对象只是作为ThreadLocalMap的一个key而存在的,现在它被回收了,那么value呢?针对这一问 题,ThreadLocalMap类在每次get(),set(),remove() ThreadLocalMap中的值的时候,会自动清理key为null的 value。如此一来,value也能被回收了。
二、控制线程
1、ForkJoin与ForkJoinPool
1)、概念
ForkJoin是由JDK1.7后提供多线并发处理框架。处理逻辑大概分为两步:
1.任务分割:Fork,先把大的任务分割成足够小的子任务,如果子任务比较大的话还要对子任务进行继续分割。
2.合并结果:join,分割后的子任务被多个线程执行后,再合并结果,得到最终的完整输出。
2)、设计思想
- 普通线程池内部有两个重要集合:工作线程集合和任务队列。
- ForkJoinPool也类似,工作集合里放的是特殊线程ForkJoinWorkerThread,任务队列里放的是特殊任务 ForkJoinTask。不同之处在于,普通线程池只有一个队列。而ForkJoinPool的工作线程ForkJoinWorkerThread每个线程内都绑定一个双端队列。
- 在fork的时候,也就是任务拆分,将拆分的task会被当前线程放到自己的队列中。
- 如果有任务,那么线程优先从自己的队列里取任务执行默认从队尾。
- 当自己队列中执行完后,工作线程会跑到其他队列的队首偷任务来执行。
eg:
package thread;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
public class ForkJoin extends RecursiveTask<Long> {
private long start;
private long end;
public ForkJoin(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long middle = (start + end) / 2;
ForkJoin leftTask = new ForkJoin(start, middle);
ForkJoin rightTask = new ForkJoin(middle + 1, end);
// 执行子任务
leftTask.fork();
rightTask.fork();
// 等待子任务执行完毕
long left = leftTask.join();
long right = rightTask.join();
return left + right; // 合并子任务的计算结果
}
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool();
ForkJoin task = new ForkJoin(1, 11l);
Future<Long> future = pool.submit(task);
try {
System.out.println(\"result: \" + future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
2、 join线程
1)作用:阻塞当前线程,优先执行join进来的线程,join放大加入的线程执行完后,被阻塞的当前线程继续执行。
eg:
package thread;
public class Join extends Thread {
public Join(String name) {
super(name);
}
@Override
public void run(){
for (int i=0; i<10; i++){
System.out.println(\"curr thread name : \"+getName()+\", r :\"+i+\", priority : \"+Thread.currentThread().getPriority());
}
}
public static void main(String[] args) throws InterruptedException {
//启动子线程,输出0-9
Join th1 = new Join(\"sub\");
th1.start();
//主线程中打印0-9
for (int k=0; k<10; k++){
if (k==5){
//k==5时,执行join方法,当前线程的打印操作停止,join线程(子线程)启动打印,子线程之间执行顺序按照优先级依次执行
Join j = new Join(\"join\");
j.start();
j.join();
}
System.out.println(\"main priority : \" + Thread.currentThread().getPriority() + \", r : \" + k);
}
}
}
输出结果:
3、yield
1)作用:执行yield的方法的线程,该线程执行任务会暂停,线程进入就绪态,其他同级别或高优先级的线程(处于就绪态的)会被操作系统调用。
eg:
package thread;
/**
* @author Administrator
*/
public class Yield extends Thread {
public Yield(String name){
super(name);
}
@Override
public void run(){
for (int i=0; i < 5; i++){
if (i==3){
//当前线程转为就绪态,同级或高优先级的线程继续执行
Thread.yield();
}
System.out.println(getName()+\":\"+i);
}
}
public static void main(String[] args) {
Yield yth = new Yield(\"y1\");
yth.start();
Yield yth2 = new Yield(\"y2\");
yth2.start();
}
}
运行结果:
4、sleep
如果需要让当前正在执行的线程暂停一段时间,并进入阻塞状态,则可以通过调用Thread类的静态sleep()方法来实现。
5、后台线程
在后台运行的一种线程,它的任务是为其他的线程提供服务,这种线程被称为“后台线程(Daemon Thread)”,又称为“守护线程”或“精灵线程”。JVM的垃圾回收线程就是典型的后台线程。后台线程有个特征:如果所有的前台线程都死亡,后台线程会自动死亡。调用Thread对象的setDaemon(true)方法可将指定线程设置成后台线程。
package thread;
public class Daemon extends Thread {
@Override
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
public static void main(String[] args) {
Daemon d = new Daemon();
d.setDaemon(true);
d.start();
//此处保证主线程不会停止,否则后台线程执行不完整就直接退出
while (true){}
}
}
注:前台线程死亡后,JVM 会通知后台线程死亡,但从它接收指令到做出响应,需要一定时间。而且要将某个线程设置为后台线程,必须在该线程启动之前设置,也就是说,setDaemon(true)必须在start()方法之前调用,否则会引发IllegalThreadStateException异常。
感谢阅读,借鉴了不少大佬资料,如需转载,请注明出处,谢谢!https://www.cnblogs.com/huyangshu-fs/p/14305755.html
来源:https://www.cnblogs.com/huyangshu-fs/p/14305755.html
本站部分图文来源于网络,如有侵权请联系删除。