Java多线程基础知识

本文详细介绍了Java中的多线程基础知识,包括进程与线程的区别,线程的并发与并行概念,以及线程的创建与使用。通过Thread类和Runnable接口两种方式创建线程,并探讨了线程的生命周期、状态转换以及线程同步机制。此外,还讲解了线程的死锁问题和同步方法。最后,提到了线程的礼让(yield)和插队(join)操作,以及用户线程和守护线程的区别。
摘要由CSDN通过智能技术生成

多线程基础知识

这是我再次学习多线程知识的一个总结,对于刚刚接触的学习者是比较友好易懂的,便于快速的理解和掌握。

一.基本概念:

1.进程:进程就是运行中的程序,当一个程序开始执行,操作系统就会给这个进程分配内存空间来执行它。而进程的执行过程是一个动态的过程,它有着自己产生、存在和小王的过程。

2.线程:线程是由进程创建的,是进程的一个实体。一个进程可以拥有多个线程,一个线程也可以去创建新的线程。

3.并发与并行

并发:同一个多个任务交替进行,造成了一种貌似同时执行的感觉,简单说单核cpu实现的多任务就是并发。(一时多发)

并行:在同一个时刻,多个任务可以同时执行,多核cpu可以实现并行。(一时一发)

二、线程的基本使用

总共由两种方法实现线程:

1.继承Thread类,重写run方法,当一个类继承它,那么这个类就是一个线程。

2.实现Runnable接口,重写run方法,这样的操作就相当于自定义的线程。

下面是Thread的接口关系图:
在这里插入图片描述
我们的业务逻辑一般写在run方法中,而run不是Thread中定义的方法,它是重写于Runnable接口方法的,最初在Runnable中定义。

实例化继承了Thread的类之后,还需要start才可以启动这个线程。启动程序的时候,main就是主线程,之后启动子线程主线程不会被阻塞,两个线程并行执行。主线程可能会提前结束,但是这并不影响子线程的生命,main挂掉之后,0号线程依然执行。

在这里插入图片描述

三、线程的底层原理

1、用start()启动线程,发生了什么?

先start,然后就会调用到我们重写的run方法。run()就是一个简单的方法,如果直接调用它,相当于还是在主线程。start() 才能真正的开启一个新的线程。
请添加图片描述
源码解释:
1.在Thread的start方法中,调用了start0()这个方法,start0()是一个本地方法,它是由JVM来调用的,我们没有办法调用这个方法,底层由 c/c++ 来实现。
在这里插入图片描述

四、线程的基本使用

1.Runnable接口的使用

使用的原因:java是单继承的,如果一个类已经继承了某一个父类,这时显然不能直接继承Thread来开启线程,就要用到Runnable接口来创建线程。

但是Runnable本身实现的方法只有一个,那就是run()方法,所以我们没办法使用start()来开启一个新的线程。
请添加图片描述
这里要使用:

Dog dog = new Dog();
Thread thread = new Thread(dog);
thread.start();
//这里创建了Thread对象,把实例化的dog对象,放到这个新的实例化线程中。因为,dog已经实现了Runnable接口,这里的底层使用了一个设计模式【代理模式】,接下来用代码模拟一下代理模式的实现。

//线程代理类,模拟了极简的Thread类
class ThreadProxy implements Runnable{
    private Runnable target=null;

    public ThreadProxy(Runnable target) {
        this.target = target;
    }
    //在这个构造器中,接收了一个实现了Runnable接口的对象,也就是上面的那一句。就这样,我们把外面的对象传到了代理类中,走到了start0()方法里。而进一步的,start0就真的开启了线程,这个时候调用重写的run方法,就是在新的线程中跑run。

    public void  start(){
        start0();
    }

    public void start0(){
        //JVM调用该方法
        run();
    }

    @Override
    public void run() {
        if (target!=null){
            target.run();
        }

    }
}

2.多线程的使用

请添加图片描述
如果在主线程中开启了线程1、2,那么,如果主线程已经结束,不会影响到子线程的执行。从某种意义上说,它们是相互独立的,有着各自的生命周期。

如果在继承了Thrad的类中,有一部分资源可以被创建的线程共享,如果此时我们多开了线程来使用这部分资源,那么就会出现线程之间抢占资源的情况,会出现重复使用的问题。这里也就引出了锁的概念。

3.线程终止

线程的停止可以有两种方法:一种是使用完成后的自然销毁,一种是通知销毁,通过使用变量控制run方法退出来停止线程。

具体的使用方法就是在线程中设置一个boolean类型的私有变量loop,用set方法使外界可以修改线程内部的loop,这样我们就可以从外界控制一个线程的生死。

4.线程插队(yield、join)

yield:线程的礼让,让出cpu资源,让其他线程先去执行,但是礼让的时间不确定,能不能成功也不确定,取决于当下cpu的资源够不够用。(这么随缘真的有用处吗?)

join:线程的插队。插队的线程一旦插队成功,则必定完成插入线程的所有任务。

5.用户线程和守护线程

用户线程:也叫做工作线程,当线程的任务执行完或被以通知方式结束。

守护线程:一般是为了工作线程服务的,当所有用户线程结束,守护线程会自动结束(垃圾回收机制)。守护的作用往往用于监控其他线程,获取其他线程的信息。

DaemonbThread.setDaemon(true);
DaemonbThread.start();
六、线程的生命周期

在这里插入图片描述
1.线程的六种状态

NEW :🐤初始状态,一个新创建的线程,还没有开始执行。

RUNNABLE :可执行状态,可能正在执行,也可能一切准备就绪在等待执行。

WAITING : 等待状态,等待其他的线程去执行特定的操作,没有时间限制

TIMED WAITING : 限时等待状态,等待其它线程去执行特定的工作,有时间限制,sleep就是典例。

BLOCKED : 阻塞状态,等待锁,以便于进入同步块。

TERMINATED : 终止状态,线程执行结束。
在这里插入图片描述
整体上可以分为两部分,顺利的流程就是:产生---->工作---->终止

不顺利就会进入下面的三种状态中。这里需要着重理解一下阻塞的含义,如果一个线程要执行的代码被其它线程锁住了,那么久阻塞了,需要等待人家解开锁后才可以执行。

非正常情况结束后,就要回到 RUNNABLE 状态,继续执行。

七、线程同步机制(Synchronized)

1.如何理解线程同步机制?

在多线程中,有一些敏感数据不能允许多个线程同时的操作和使用,这时候就要用到线程同步机制。它可以确保在同一时间,只能有一个线程可以访问这些资源,这样一来就保证了数据的完整性。

线程同步的本质:当一个线程在对内存进行操作时,其他的线程就不能对这个内存地址进行操作。

2.互斥锁

Java中,引入了互斥锁的概念,用来保证数据的完整性。只要有一个称为“互斥锁”的标记,就可以确保只有一个线程访问该对象。

同步方法,如果是非静态的,锁就是this或者是其他对象。如果是静态的,锁就是当前类本身。

synchronized (this){   
 //非静态(没用static修饰),要锁的内容、数据
}
synchronized (MainActivity.class){   
 //静态(用static修饰),要锁的内容、数据
}

实现锁的具体步骤:

1.先分析出来要上锁的代码

2.选择同步代码块或者同步方法

3.保证多个线程的锁对象时同一个即可

3.线程的死锁

当多个线程都占用了对方的锁资源,但是彼此都互不相让,就导致了死锁。

下面就是死锁的简单示例:

若flag为true,A线程先得到o1对象锁,然后尝试拿到o2对象锁。拿不到o2就会阻塞。

若flag为false,B线程先得到o2对象锁,然后尝试拿到o1对象锁。拿不到o2就会阻塞。

当A、B线程各自拿到一个锁,就会死锁。

 boolean flag=true;
        if (flag){
            synchronized (o1){
                synchronized (o2){
                }
            }
        }else{
            synchronized (o2){
                synchronized (o1){
                }
            }
        }

4.释放锁

锁的释放有四种情况:

1.当前线程的同步方法执行结束

2.线程在同步代码块中遇到了break、return,被迫结束。

3.线程在同步代码块中遇到了未处理的Error、Exception,异常结束。

4.线程在同步代码块中执行了线程对象的wait()方法,线程会暂停并释放锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值