(若使用图片侵权,请联系我删除)
先简单解释一下线程和进程:比如QQ是进程,那么一条条的聊天窗口就属于线程。大家也可以去百度百科搜一下,我这就不多提了。
引入:多线程的目的在于如何更好的利用CPU的资源。
多线程:指一个程序运行时产生了不止一个线程
并发:通过运用CPU调度算法,让表面看上去同时执行,实际上从CPU操作层面看不是真正的同时执行
并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
(本图中第一种情况是并发,第二种情况是并行)
线程安全:我们经常看到这个名词在某段代码身上。它指的是在并发的情况下,某代码经过多线程的使用时,线程的调度顺序不会改变最终运行结果;反之线程不安全就意味着线程的调度顺序会改变最终运行结果。(比如上一幅图中,假如出现了多个人同时碰到了咖啡机的情况怎么办?难道谁手快,谁就可以先喝咖啡吗?那么干脆大家别排队了直接抢就行了!下面的同步就是专门解决这类问题的发生)
同步:Java中的同步是指通过人为的控制和调度,保证公共/共享资源的多线程访问成为线程安全,以保证最终结果的准确。
线程状态 | 描述 |
---|---|
New | 尚未启动的线程处于此状态 |
Runnable | Java虚拟机中正在执行的线程处于此状态 |
Blocked | 被阻塞等待监视器锁的线程处于此状态 |
Waiting | 无限期地等待另一个线程执行特定操作的线程处于此状态 |
Timed_Waiting | 在指定的等待时间内等待另一个线程执行操作的线程处于此状态 |
Terminated | 已退出的线程处于此状态 |
monitor 是应用于同步问题的人工线程调度工具。Java每个对象都有一个监视器,来监测并发代码的重入。在非多线程编码时该监视器不发挥作用;反之如果在 synchronized 范围内,则监视器发挥作用。
synchronized 单独使用
- ??????? 代码块:相当于让 lock 锁定了此块,即同一时间内只有一个线程执行此块的内容
- ??????? 方法:相当于让 lock 锁定了此方法,即同一时间内只有一个线程执行此方法。进一步假设它是 static 方法的话,那则会锁定此类的所有实例。 ??????
继承 Thread 类 | 实现 Runnable 接口 | |
---|---|---|
继承关系 | 因为Java是单继承机制,所以有限 | 通过实现接口达到多继承 |
具体如何产生多线程 | 如果产生Runnable实例对象,就必须产生多个Runable实例对象,然后再用Thread来产生多个线程 | 只需要创建一个此实现类的实例,然后用这个实例对象产生多个线程(这体现了资源的共享性) |
相同点 | 无论哪种方法都必须要用Thread或其子类产生线程,然后再调用start()方法 |
Thread具备创建和运行一个线程所必需的基本内容。Thread类中最重要的方法是run(),它把用于实现一个线程实际功能的代码都放在了run方法内。因此当继承Thread类后就需要重写这个方法,来把自己希望并行处理的代码写在run方法内。这样这段代码就能与程序中的其它线程“同时”执行了。
1.
public static Thread.yield();
//让当前线程可转让CPU控制权,让别的就绪状态(Runnable)线程运行(切换)
2.
public static Thread.sleep();
//在一个线程中调用other.join(),将等待other执行完后才继续本线程
3.4.
public join()
public interrupte()
//以上两个函数皆可以被打断
要想启动线程的运行,首先创建一个线程类的对象,并通过对象引用去调用start()方法来开启线程的执行,然后由线程执行机制通过start()方法来调用run()方法。倘若不调用start()方法,则线程永远不会启动。而Thread类中的run方法从来不会被显式调用,start方法也不会被重写。
在程序中使用 start() 方法启动一个线程后,程序控制权立刻返回给此调用方法,然后新线程与调用方法开始并发地执行。无论程序启动了多少个线程,这些线程都共享着CPU的处理资源,而Java的线程调度机制负责这些线程之间的切换。从宏观上看,这些线程是并行执行的,但在单CPU系统中,任意时刻里都只有一个线程在使用CPU。(若线程调度机制是不确定的,则线程的执行顺序也是不确定的,这样就导致程序每次运行结果都不尽相同)
Runnable接口很简单,它只包含了run方法
1.
public Thread(Runnable target)
//Thread 类的构造方法