先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
正文
Runnable
会被包装成一个实现了Callable
的RunnableAdapter
赋值给callable
。适配的过程也可以看出result
是怎么传进去就会怎么返回。
//Executors
public static Callable callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
//将Runnable适配成Callable
return new RunnableAdapter(task, result);
}
//适配器、典型的适配器模式
static final class RunnableAdapter implements Callable {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
//传入的result并没有做任何处理
return result;
}
}
所以官方给的函数AbstractExecutorService#submit(java.lang.Runnable, T)
,也可以传入Runnable
类型的任务和result
,不过只能判断任务是否完成或者取消任务,外部get
的result
还是传进去的result
,没有太大的意义。
3、核心函数
(1)get阻塞获取结果
get()
有两种,一种是会等待计算结束返回,一种是加了超时时长timeout
,get线程等待timeout
时长,如果此时还没有完成就抛出异常TimeoutException
。
/**
-
会一直阻塞到计算结束,可以被打断
-
@throws CancellationException {@inheritDoc}
*/
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
//运行未完成,放入等待栈中
s = awaitDone(false, 0L);
return report(s);
}
public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
if (unit == null)
throw new NullPointerException();
int s = state;
if (s <= COMPLETING &&
(s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
//阻塞时间到,若还没有完成就抛异常
throw new TimeoutException();
return report(s);
}
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
//如果是正常结束,返回结果
return (V)x;
//取消或者中断的就抛出取消异常
if (s >= CANCELLED)
throw new CancellationException();
//其他状态的抛异常EXCEPTIONAL
throw new ExecutionException((Throwable)x);
}
awaitDone阻塞等待
阻塞的核心代码就是awaitDone
,get时若正在计算,将会被放入等待栈阻塞,直到超时时间到,或者被唤醒,或者被中断,然后返回当前的状态。
-
当前get线程被打断,删除等待节点,并抛出
InterruptedException
。 -
若此时
s > COMPLETING
有可能完成、取消、中断,将等待节点(WaitNode
)的thread设置为null,并返回当前状态。 -
若
s == COMPLETING
说明正在完成,暂停当前get线程,让出对cpu
的占用,执行其他get线程。 -
若当前get线程还没有入等待栈,实例化一个
WaitNode
,并cas
入栈。 -
最后阻塞,阻塞分为时间阻塞和永久阻塞,阻塞时间到,删除等待节点并返回当前状态。
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
//循环阻塞,循环终止- 阻塞时间到,或者被唤醒,然后返回当前的状态
for (;😉 {
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) {
//完成,取消,中断
if (q != null)
q.thread = null;
//返回结果状态
return s;
}
else if (s == COMPLETING) // cannot time out yet
//正在完成,暂停当前线程,执行其他get线程
Thread.yield();
else if (q == null)
//NEW 状态,新建一个WaitNode
q = new WaitNode();
else if (!queued)
//cas入栈
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
else if (timed) {
//需要时间阻塞
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
//不需要等待,删除等待节点
removeWaiter(q);
return state;
}
//阻塞一段时间
LockSupport.parkNanos(this, nanos);
}
else
//timed false 会一直阻塞到 计算完成, 需要唤醒
LockSupport.park(this);
}
}
/**
-
栈,node.thread=null的节点会被删除
-
@param node
*/
private void removeWaiter(WaitNode node) {
if (node != null) {
node.thread = null;
retry:
for (;😉 {
// restart on removeWaiter race
//循环删除node.thread = null的节点
for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
s = q.next;
if (q.thread != null)
pred = q;
else if (pred != null) {
pred.next = s;
if (pred.thread == null) // check for race
continue retry;
}
else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
q, s))
continue retry;
}
break;
}
}
}
(2)cancel取消任务中断工作线程
调用cancel()可能是被中断(mayInterruptIfRunning=true
)或者是主动取消(mayInterruptIfRunning=false
)。
-
中断取消,设置
state
为INTERRUPTING
,并调用runner.interrupt()
中断当前运行线程,设置state
为INTERRUPTED
,最后清空等待栈中所有阻塞节点并唤醒所有等待的线程。 -
主动取消,设置
state
为CANCELLED
,最后清空等待栈中所有阻塞节点并唤醒所有等待的线程。
从代码可以看出只有state
为NEW
才能被取消。
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
//cass设置 state为INTERRUPTING or CANCELLED
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
//状态没有修改成功返回false,取消失败
return false;
try { // in case call to interrupt throws exception
//如果是被打断的 就调用t.interrupt();中断线程
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
//中断当前线程
t.interrupt();
} finally { // final state
//设置state为中断
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
//最后 删除并唤醒所有等待的线程
finishCompletion();
}
return true;
}
//删除并唤醒所有等待的线程
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
//循环cas WaitNode 为null,删除所有等待的线程
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;😉 {
Thread t = q.thread;
if (t != null) {
q.thread = null;
//循环唤醒唤醒
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null)
//最后了,break
break;
q.next = null; // unlink to help gc 设置为null 有利于gc
q = next;
}
break;
}
}
//钩子函数
done();
callable = null; // to reduce footprint
}
(3)run执行任务代码并唤醒所有等待线程
FutureTask
是会被传给ThreadPoolExecutor.Worker
,由线程池启动工作线程,然后调用FutureTask
的run()
函数,run()
又调用callable.call()
。run()
会将结果设置给outcome
。
public void run() {
//新任务–>执行UNSAFE.compareAndSwapObject(this, runnerOffset,
// null, Thread.currentThread()))
//新任务会将当前线程设置给runner 这里的作用是乐观锁,保证下面的执行流程是只有一个线程
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//调用callable的call,并设置返回值
//如果传进来的任务是Runnable,会被转换成callable
result = c.call();
//若运行异常,ran=false,异常会被捕获处理
//所以传进来的任务的run或者call代码块最好try-catch下
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
//设置异常给outcome
setException(ex);
}
if (ran)
//运行正常完成,设置结果给outcome
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
//最后 runner=null 相当于是释放锁
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
//如果状态是被打断,让出cpu
handlePossibleCancellationInterrupt(s);
}
}
执行细节如下:
-
新任务
CAS
设置当前线程给runner
,这里的作用是乐观锁保证下面的执行流程只有一个线程,并且外部可以通过runner
随时中断执行。 -
直接调用
callable.call()
执行任务代码。 -
中途出现异常,将异常设置给
outcome
,状态流转为异常完成,并唤醒所有等待的线程。
protected void setException(Throwable t) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
//设置异常
outcome = t;
//设置异常状态
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
//唤醒所有线程
finishCompletion();
}
}
- 正常运行完毕将运行结果
result
设置给outcome
,状态流转为正常完成,并唤醒所有等待的线程。
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
//设置为完成状态
outcome = v;
//设置正常状态
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
//完成操作-删除并唤醒所有等待的线程
finishCompletion();
}
}
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
//循环cas WaitNode 为null,删除所有等待的线程
//这里cas删除 其实是为了if里面的操作线程安全无锁
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;😉 {
Thread t = q.thread;
if (t != null) {
q.thread = null;
//循环唤醒唤醒
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null)
//最后了,break
break;
q.next = null; // unlink to help gc 设置为null 有利于gc
q = next;
}
break;
}
}
//钩子函数
done();
callable = null; // to reduce footprint
}
- 最终
runner
设置为null
,相当于释放锁;如若此时状态为被打断状态INTERRUPTING
,需要让出cpu
。
private void handlePossibleCancellationInterrupt(int s) {
// It is possible for our interrupter to stall before getting a
// chance to interrupt us. Let’s spin-wait patiently.
if (s == INTERRUPTING)
while (state == INTERRUPTING)
//暂停当前线程,让出cpu时间片
Thread.yield(); // wait out pending interrupt
}
(4)runAndReset重复执行
runAndReset()
和run()
类似,但是没有把result
设置给outcome
,函数返回为boolean
,用于是否重复执行。
protected boolean runAndReset() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
try {
最后
我还通过一些渠道整理了一些大厂真实面试主要有:蚂蚁金服、拼多多、阿里云、百度、唯品会、携程、丰巢科技、乐信、软通动力、OPPO、银盛支付、中国平安等初,中级,高级Java面试题集合,附带超详细答案,希望能帮助到大家。
还有专门针对JVM、SPringBoot、SpringCloud、数据库、Linux、缓存、消息中间件、源码等相关面试题。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
lean`,用于是否重复执行。
protected boolean runAndReset() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
try {
最后
我还通过一些渠道整理了一些大厂真实面试主要有:蚂蚁金服、拼多多、阿里云、百度、唯品会、携程、丰巢科技、乐信、软通动力、OPPO、银盛支付、中国平安等初,中级,高级Java面试题集合,附带超详细答案,希望能帮助到大家。
[外链图片转存中…(img-6FyTfKL8-1713600667162)]
还有专门针对JVM、SPringBoot、SpringCloud、数据库、Linux、缓存、消息中间件、源码等相关面试题。
[外链图片转存中…(img-8YyZjvPH-1713600667163)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-M9GmQPqi-1713600667163)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!