Java并发编程---Java多线程基本概念,实践出真知

 public static void main(String[] args) throws ExecutionException, InterruptedException {
    UseThread useThread=new UseThread();
    useThread.start();
    UseRun useRun=new UseRun();
    new Thread(useRun).start();
    UseCall useCall=new UseCall();
    FutureTask<String> futureTask=new FutureTask<>(useCall);
    new Thread(futureTask).start();
    System.out.println(futureTask.get());
}

}


Callable和Runnable实现的方法其实可以看做一种方式,因为在启动线程的时候Callable是放到FutureTask里面的,我们去看看FutureTask是什么东西他是个泛型类,实现了RunnableFuture这个泛型接口,RunnableFuture这个接口又继承了Runnable,和Future,所以我们可以把Runnable和Callable看成一种方式,Callable这种方式是怎么拿到返回值的呢?

futureTask.get()拿到就是返回值,首先我们看一看Future这个接口都有什么方法 ![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/09ac0c043c7a4dd1bc2fe9183dd0a879~tplv-k3u1fbpfcp-zoom-1.image) 我们再去看实现 ![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/545cfd8cb61d45fead3685b1f5d241da~tplv-k3u1fbpfcp-zoom-1.image) 它会先判断这个任务执行的状态是否完成,如果没有完成它会进入等待完成这个方法

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
            Thread.yield();
        else if (q == null)
            q = new WaitNode();
        else if (!queued)
            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
            LockSupport.park(this);
    }
} 

它会一直等待执行完成 完成之后它会 执行report方法,咱再看report方法 ![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4a80dd6774504bbf858402aefda5d6bf~tplv-k3u1fbpfcp-zoom-1.image)

然后我们再去看看Run方法

public void run() {
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 {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}


它会把Call的返回值通过set方法赋值给outcome,get的时候再把outcome返回回去

protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}


这样就 能拿到Callable的返回值了,在这里我们要区分Thread和Runnable,Thread是唯一一个对操作系统线程的抽象,而Runnable和Callable是对任务的抽象,一定要区分

2.2 线程安全的停止工作
-------------

有开始就有结束,怎样才能让Java里的线程安全的停止工作呢stop()还是isInterrupted( ),static 方法interrupted()?我们要深了解这些方法 一般情况下,Thread的run方法执行完毕,或者 抛出了异常,这个线程就在执行完毕,自己就停止了,这是一般情况下,但是我们往往因为业务的需求,需要在满足某种条件的时候,去手动停止这个线程,这个时候我们应该怎么办呢?首先我们还是去看代码去看看Thread里有什么方法 ![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a6ef0af5e3874180a8dd000df9ca7474~tplv-k3u1fbpfcp-zoom-1.image) 我们看到了stop(),destroy(),还有suspend(),但是他们都被@Deprecated注解了,JDK就告诉我们这几个方法就不要用 线程的挂起函数suspend(),这个线程在执行挂起的时候,线程不会释放资源,比如它在执行的时候拿到一个锁,挂起的时候他不会释放这个锁,这样就很有可能会导致死锁的问题 线程的停止函数stop(),这个函数是极其野蛮的,你调用这个函数,他会立马把这个线程干掉,他不会 管你这个线程的资源是否正常的释放,比如你在一个线程里写一个文件,写到一半的时候你调用这个方法,造成文件不能正常结束,而且线程里占据操作系统的资源文件句柄啥的没有得到释放 resume是唤起挂起线程的,和suspend配对使用的 其实我们在终止线程的时候,有这么几个方法可以用 ![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c1286a4ed4a14671b4173790072d1863~tplv-k3u1fbpfcp-zoom-1.image) interrupt是终止线程,interrupted,isInterrupted是获取线程是否终止 ,interrupt终止线程是一种协作方式不是那种抢占式,话不多说上代码,

public class EndThread {
private static class UseThread extends Thread{
@Override
public void run() {
super.run();
while(true){
System.out.println(“EndThread:emmmmmm”);
}
}
}

public static void main(String[] args) throws InterruptedException {
    UseThread useThread=new UseThread();
    useThread.start();
    Thread.sleep(30);
    useThread.interrupt();
}

}


这段代码是在主线程里面新启动一个线程,主线程休眠30ms去调用useThread的interrupt(),结果怎么样,结果useThread根本不鸟你,一直在执行,我们把代码做一下更改

private static class UseThread extends Thread{
@Override
public void run() {
super.run();
// while(true){
System.out.println(“EndThread:”+isInterrupted());
while(!isInterrupted()){
System.out.println(“EndThread:emmmmmm”);
}
System.out.println(“EndThread:”+isInterrupted());
}
}


我们发现它终止了跳出了循环 ![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2f2ac8c7c2fb4b798b9de3eceb07fc81~tplv-k3u1fbpfcp-zoom-1.image) ![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1dce2fbaa94f4d0b873a3066562c6ac7~tplv-k3u1fbpfcp-zoom-1.image) 我们发现在Java里Thread的interrupt方法只是将中断信号由false改为了true而已,如果线程中没有对这个信号 做任何处理,它是不会终止这个线程的,所以这个 interrupt是协作式的,不是抢占式的 细心的同学可能发现了,获取线程是否中断,有两个方法,一个是 Thread的成员方法 isInterrupted,一个是静态方法interrupted,这两个方法有什么区别呢, interrupted在获取这个线程状态的时候,如果这个中断状态是true,他会获取这个状态的同时,把这个状态设置成false 上面的代码,最终的打印结果为true,我们再改一下代码瞧一瞧

private static class UseThread extends Thread{
@Override
public void run() {
super.run();
// while(true){
System.out.println(“EndThread:”+isInterrupted());
// while(!isInterrupted()){
while(!Thread.interrupted()){
System.out.println(“EndThread:emmmmmm”);
}
System.out.println(“EndThread:”+isInterrupted());
}
}


![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ce04c2facf2b48deb4375782dda0f6f9~tplv-k3u1fbpfcp-zoom-1.image)

2.3 深入理解Thread的run()和start()
----------------------------

run方法和我们普通类里的成员方法是没什么区别的,start方法我们点进去也没什么东西,start方法最后执行的是native方法stat0,我们可以调用run,话不多说上代码

private static class UseThread extends Thread{
@Override
public void run() {
super.run();
for (;😉{
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

最后

对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。

同时我经过多年的收藏目前也算收集到了一套完整的学习资料以及高清详细的Android架构进阶学习导图及笔记免费分享给大家,希望对想成为架构师的朋友有一定的参考和帮助。

下面是部分资料截图,诚意满满:特别适合有开发经验的Android程序员们学习。

CodeChina开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》

不论遇到什么困难,都不应该成为我们放弃的理由!

有开发经验的Android程序员们学习。

[外链图片转存中…(img-ZA1vmkN2-1630932173993)]

CodeChina开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》

不论遇到什么困难,都不应该成为我们放弃的理由!

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言,一定会认真查询,修正不足,谢谢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值