JAVA多线程基础

基础概念

进程:简单来说就是计算机内存中运行的应用程序,有自己独立的地址空间,并且不同进程的地址空间是相互隔离的,是资源分配的最小单位。

线程:是程序中的顺序控制流,表示程序的执行流程,本身需要依靠程序(进程)进行运行,只能使用分配给程序的资源和环境,是CPU调度的最小单元。

单线程:程序中只存在一个线程,实际上通常main主方法就是一个主线程。

多线程:通常为了更好地使用CPU资源,在一个程序中运行了多个任务(也就是指这个程序或进程在运行时产生了不止一个线程)

并行:多个CPU实例或者多台机器同时执行一段处理逻辑,是真正的同时执行。

并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。

线程安全:通常指在并发情况下,如果一段代码在多线程下执行和在单线程下执行永远都能获得一致的结果,那么就表明这段代码是线程安全的。

同步:通常指通过人为地控制和干涉,保证多线程情况下对于共享资源的访问变得线程安全,从而保证程序最终执行结果的准确。

进程和线程的区别:

  1. 进程是资源的分配和调度的一个独立单元,而线程是CPU调度的基本单元。
  2. 同一个进程中可以包括多个线程,并且线程共享整个进程的资源(寄存器、堆栈、上下文),一个进程至少包括一个线程。
  3. 进程拥有自己独立的地址空间,包含程序内容和数据,并且不同进程的地址空间都是相互隔离的。而同一进程中的线程共用相同的地址空间,同时共享进程所拥有的内存和其他资源。
  4. 进程之间的切换开销大,而线程切换开销比较小。

多线程的作用:

  1. 发挥多核CPU的优势
    单核CPU上所谓的“多线程”那是假的多线程,同一时间处理器只会处理一段逻辑,只不过线程之间切换得比较快,看着像多个线程“同时”运行罢了。

  2. 防止阻塞
    多条线程同时运行,哪怕其中某一条线程的代码执行读取数据阻塞,也不会影响其他任务的执行。

  3. 便于建模
    假设有一个大的任务A,单线程编程的话就需要考虑得很多,建立整个程序模型相对来说比较麻烦,但是如果把这个大的任务A分解成几个小的任务B,任务C,任务D然后分别建立程序模型,并通过多线程分别运行这几个任务,相对来说就简单多了。

线程的状态

1. 创建(NEW)状态

线程在被创建后,进入NEW状态。

2. 就绪(RUNNABLE)状态

调用start()方法,进入就绪状态,等待系统调度,分配资源,此时的调度顺序是无法确定的。

3. 运行(RUNNING)状态
  • 执行run()方法,获得CPU执行时间片,进行运行状态
  • 调用yield()方法可以让一个running状态的线程转入runnable
4. WAITING状态

调用wait(),join()方法,进入主动等待状态,等待notify(),notifyAll()被唤醒

5. TIME WAITING

调用sleep(senconds),wait(seconds),join(seconds),主动睡眠

6. 阻塞(BLOCKED)状态

被同步块阻塞,或者遇到IO阻塞,进入阻塞状态,暂时停止执行,可以将资源交给其他线程使用

7. 终止(DEAD)状态

线程销毁

线程在Running过程中可能会遇到的阻塞(Blocked)情况

  1. 调用join()或者sleep()方法,sleep()时间结束或被打断,join()中断,IO完成都会回到Runnable状态,等待CPU的再次调度
  2. 调用wait(),使该线程处于等待池(wait blocked pool),直到调用notify()/notify all(),线程被唤醒再被放到锁定池(lock blocked pool),释放同步锁使线程回到可运行状态
  3. 对Running状态的线程加同步锁(Synchronized),使其进入锁定池(lock blocked pool),同步锁被释放进入可运行状态

常用方法

静态方法

currentThread()方法

可以返回代码段正在被哪个线程调用的信息。

sleep()方法
  1. 让线程睡眠,交出CPU时间片,让CPU去执行其他的任务
  2. 但是有一点要非常注意,sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象
yield()方法
  1. 调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程
  2. 它跟sleep方法类似,同样不会释放锁,但是yield不能控制具体的交出CPU的时间
  3. yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会
  4. 调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的

对象方法

start()方法

start()用来启动一个线程,当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要的资源

run()方法
  1. run()方法是不需要用户来调用的,当通过start方法启动一个线程之后,当线程获得了CPU执行时间,便进入run方法体去执行具体的任务
  2. 继承Thread类必须重写run方法,在run方法中定义具体要执行的任务
getId()方法

getId()的作用是取得线程的唯一标识

isAlive()方法
  1. 方法isAlive()的功能是判断当前线程是否处于活动状态
  2. 什么是活动状态呢?活动状态就是线程已经启动且尚未终止。线程处于正在运行或准备开始运行的状态,就认为线程是“存活”的
join()方法

在很多情况下,主线程创建并启动了线程,如果子线程中药进行大量耗时运算,主线程往往将早于子线程结束之前结束。这时,如果主线程想等待子线程执行完成之后再结束,比如子线程处理一个数据,主线程要取得这个数据中的值,就要用到join()方法了。方法join()的作用是等待线程对象销毁

getName()和setName()方法

用来获取或者设置线程名称

getPriority()和setPriority()方法

用来获取和设置线程优先级

setDaemon()和isDaemon()方法

用来设置线程是否成为守护线程和判断线程是否是守护线程

创建线程的方式

  1. 继承Thread类
/**
 * 自定义线程
 */
class MyThread extends Thread{
    /*线程名称*/
    private String name;

    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println("名称" + name + "的线程ID是:" + Thread.currentThread().getId());
    }
}
  1. 实现Runnable接口
class MyRunnable implements Runnable{

    private String name;

    public MyRunnable(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println("名字" + name + "的线程ID是: " + Thread.currentThread().getId());
    }
}
  1. 通过线程池创建
//创建一个线程池
ExecutorService threadPool = Executors.newFixedThreadPool(3);
threadPool.execute(new Runnable() {
    @Override
    public void run() {
        System.out.println("==========================");
    }
});

暂停线程

调用interrupt()方法

它并不是中断某个线程!它只是线线程发送一个中断信号,让线程在无限等待时(如死锁时)能抛出抛出,从而结束线程,但是如果你吃掉了这个异常,那么这个线程还是不会中断的。

停止线程

在Java中有以下3种方法可以终止正在运行的线程

  1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止
  2. 使用stop方法强行终止线程,但是不推荐使用这个方法,因为stop和suspend及resume一样,都是作废过期的方法,使用他们可能产生不可预料的结果
  3. 使用interrupt方法中断线程,但这个不会终止一个正在运行的线程,还需要加入一个判断才可以完成线程的停止

最后,再附上一张整理的思维导图:


JAVA多线程.png
最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容