俗话说好记性不如lai笔头,子曰:温故而知新~ 言归正传,本系列将从以下方面复习Java多线程编程相关的知识。
- 多线程入门
- 线程安全
- 多线程之间的通讯
- 并发编程
- 线程池
一、多线程入门
- 线程与进程的区别
- 为什么使用多线程
- 如何创建线程
- 线程的几种状态
- 守护线程与非守护线程
- 线程常用API
1.线程与进程的区别
进程:个人理解进程是指正在运行的一个应用程序;定义为:具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的独立单位。
线程:是进程的一个实体,是CPU调度和分派的基本单位,比进程更小的能独立运行的基本单位;或者说线程是进程的一条执行路径。
区别:
a. 根本区别:进程是资源分配的基本单位,线程是程序执行的基本单位。
b. 主要差别:它们是操作系统不同的资源管理方式。系统会为每个进程分配不同的内存空间,进程间切换会有比较大的开销;同一进程内的线程共享进程的内存资源,除了CPU外,系统不会给线程分配内存,每个线程有自己独立的运行栈和程序计数器,线程间切换开销小。
2.为什么使用多线程
使多 CPU系统更加高效,提高工作效率。例如多线程上传或下载资源。
3.如何创建线程
a.继承Thread类,重写run方法。
创建CreateThread类:
public class CreateThread extends Thread {
public void run() {
for (inti = 0; i< 10; i++) {
System.out.println("i:" + i);
}
}
}
开启线程方式:
public static void main(String[] args) {
CreateThread createThread = new CreateThread();
createThread.start();
}
b.实现Runnable接口,重写run方法(推荐)
创建CreateRunnable类:
public class CreateRunnable implements Runnable {
@Override
public void run() {
for (inti = 0; i< 10; i++) {
System.out.println("i:" + i);
}
}
}
开启线程:
public static void main(String[] args) {
CreateRunnable createThread = new CreateRunnable();
Thread createThread = new Thread(createThread);
createThread.start();
}
c.使用匿名内部类
Thread thread = new Thread(new Runnable() {
public void run() {
for (int i = 0; i< 10; i++) {
System.out.println("i:" + i);
}
}
});
thread.start();
为什么推荐第二种,因为Java的单一继承,多实现原则。第三种不方便管理,容易造成资源浪费。
注意:别忘调用Thread类的start()方法开启线程
4.线程的几种状态
图片来源于网络
大体上来说线程从创建到结束有5种状态。分别是新建状态(new)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked)、死亡状态(Dead)
a.新建状态:当用new操作符创建一个线程实例时,此时Thread的run方法还未执行
b.就绪状态:通过thread实例调用start()方法即是启动了线程,创建线程运行的系统资源,并调度运行run()方法,当start方法返回后,线程就处于就绪状态
处于就绪状态的线程不一定立即运行run方法,还必须同其他线程竞争CPU时间,只有获得CPU执行时间才可以运行线程。
c.运行状态:当线程获得CPU时间后,进入运行状态,真正开始执行run()方法
d.阻塞状态:线程运行中有多种情况会导致阻塞
- 通过调用sleep方法进入睡眠状态或join()或发出了I/O请求时,线程会进入到阻塞状态,当sleep状态超时,join等待线程终止或者超时、或IO处理完毕时,线程重新转入就绪状态。
- 等待阻塞:运行中的线程执行wait()方法,使本线程进入到等待阻塞状态
- 同步阻塞:线程在获取synchronized同步锁失败(因为锁被其他线程占用),它会进入同步阻塞状态
e:死亡状态:线程执行完了或因异常退出了run()方法,该线程结束生命周期。
为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true; 如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,则返回false.
5.守护线程与非守护线程
Java中有两种线程:一种是用户线程,另一种是守护线程。
用户线程:用户自定义的线程,主线程停止,用户线程不会停止
守护线程:当进程不存在或主线程停止,守护线程被停止
使用setDaemon(true)方法设置为守护线程。
6.线程常用API
a.setPriority():设置线程的优先级,范围为1-10,其中10最高,默认值为5
b.join():线程a,b;在b中调用a.join()会等a执行完成才开始执行b线程,目的是将两个交替执行的线程合并为顺序执行。
c.yield():Thread.yield()方法的作用:暂停当前正在执行的线程,并执行其他线程。(可能没有效果)
yield()让当前正在运行的线程回到可运行状态,以允许具有相同优先级的其他线程获得运行的机会。因此,使用yield()的目的是让具有相同优先级的线程之间能够适当的轮换执行。但是,实际中无法保证yield()达到让步的目的,因为,让步的线程可能被线程调度程序再次选中。
结论:大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。
欢迎关注个人公众号,技术干货分享: