进程:进程是具有独立功能的程序在一个数据集合上运行的过程,是系统进行
资源分配
和调度
的独立单位。每一个进程都有它自己的内存空间
和系统资源
线程:线程作为资源调度
的基本单位,是程序的执行单元,执行路径(单线程:一条执行路径,多线程:多条执行路径)。是程序使用CPU
的最基本单位
-
线程有3个基本状态:执行、就绪、阻塞
并行:
同一时间
能够处理多个事件并发:
同一时间间隔
能够处理多个事件,在事件间隔内可能是串行执行的-
Java实现多线程有3种方法
- 继承Thread,重写run(),无返回值
- 实现Runnable接口,重写run(),无返回值
- 实现Callable接口,实现call()方法,并且有返回值
-
创建线程的三种方式的对比
采用实现Runnable、Callable接口的方式创建多线程时,优势是:
线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。劣势是:
编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。
-
使用继承Thread类的方式创建多线程时优势是:
编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。- 劣势是:
线程类已经继承了Thread类,所以不能再继承其他父类。
- 劣势是:
-
run()和start()方法区别:
- run():仅仅是封装被线程执行的代码,直接调用是普通方法
- start():首先启动了线程,然后再由jvm去调用该线程的run()方法
package algorithm;
import lombok.Data;
/**
* 循环输出 0 1 a 2 3 b ..... 50 51 z
* <p>
* author: TAOPENG
* time : 2019/3/12
**/
public class ThreadNotification {
@Data
private class Tag {
private Boolean tag = false;
}
private final Tag tag = new Tag();
class DemoOne implements Runnable {
int i = 0;
@Override
public void run() {
while (i < 52) {
synchronized (tag) {
while (tag.getTag()) {
try {
tag.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print(" " + i + " " + (i + 1));
i = i + 2;
tag.setTag(true);
tag.notify();
}
}
}
}
class DemoTwo implements Runnable {
char c = 'a';
@Override
public void run() {
while (c <= 'z') {
synchronized (tag) {
while (!tag.getTag()) {
try {
tag.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print(" " + (c++));
tag.setTag(false);
tag.notify();
}
}
}
}
public static void main(String[] args) {
ThreadNotification threadNotification = new ThreadNotification();
DemoOne demoOne = threadNotification.new DemoOne();
DemoTwo demoTwo = threadNotification.new DemoTwo();
Thread threadOne = new Thread(demoOne);
Thread threadTwo = new Thread(demoTwo);
threadOne.start();
System.out.println("thread 1启动");
threadTwo.start();
System.out.println("thread 2启动");
}
}