进程
每个独立运行的程序称为进程。进程是程序的一次执行过程,它经历了从代码加载、执行到执行完毕的一个完整的过程,这个过程也是进程本身从产生、发展到消亡的过程。在操作系统中,进程是进行系统资源分配、调度和管理的最小单位。进程在执行过程中拥有独立的内存单元。
线程
线程是cpu调度和分配的基本单位,它可与同属一个线程的其他的线程共享进程所拥有的全部资源,多个线程共享内存,从而极大地提高了程序的运行效率。线程是比进程更小的执行单位。
一个或多个的线程构成了一个进程,如果一个进程没了,那么线程肯定会消失,只有多有的线程都结束了,线程才会结束!
进程和线程的区别
多线程是实现并发机制的一种有效手段。进程和线程一样,都是实现并发的一种基本单位。区别主要体现:
- 同样作为基本的执行单元,线程是划分得比进程更小的执行单位。
- 每个进程都有一段专用的内存单元,线程是划分得比进程更小的执行单位。
比较点 | 进程 | 线程 |
代码和数据空间 | 每个进程独立 | 在同一个进程内共享 |
切换开销 | 大 | 小 |
多线程创建方式之一
----继承Thread 类
- 定义一个类使之继承Thread类
- 覆写Thread类的public void run()方法,需要多线程处理的代码必须写在run()方法内部。
public class ThreadDemo01 {
public static void main(String[] args) {
// 创建线程对象
MyThread01 mt = new MyThread01();
// 开启线程
mt.start();
// 错误的开启方式
// mt.run();
for (int i = 0; i < 1000; i++) {
System.out.println("Main Run :" + i);
}
}
}
class MyThread01 extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("My Thread01 Run: " + i);
}
}
}
注意:
启动多线程必须是通过线程类的对象来调用start()方法。不能直接调用run()方法,如果直接调用run()则仍然是单线程,没有启动多线程。通过start()方法,启动一个子线程,子线程会直接运行run()方法内部的代码。
多线程创建方式之二
----实现Runnable接口
- 定义一个类,实现Runnable接口,实现接口的run()方法,run()方法内部定义多线程要运行的代码
- 创建一个Runnable接口实现类的对象
- 创建一个Thread类的对象,用刚才Runnable接口实现类对象作为构造函数参数
- 调用Thread对象的start()方法来启动线程。
public class RunnableDemo01 {
public static void main(String[] args) {
// 创建实现Runnable 线程的子类实例
MyThread02 mt = new MyThread02();
// 创建线程,把子类对象传递进去
Thread t = new Thread(mt);
// 开启线程
t.start();
for (int i = 0; i < 1000; i++) {
System.out.println("Main Run :" + i);
}
}
}
class MyThread02 implements Runnable { // 子类继承父类 实训Runnable 接口
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("My Thread01 Run: " + i);
}
}
比较:
比较点 | Thread | Runnable |
继承 | 单继承,有局限性 | 可实现多继承,使用灵活,易扩展 |
数据 | 每个线程都有独立的数据 | 每个线程都共享同一份数据 |
Thread类的一些方法(常用)
public void start() | 使该线程可以执行 |
public static Thread currentThread() | 返回对当前正在执行的线程对象的引用 |
public boolean isAlive() | 测试线程是否处于活动状态 |
public Thread.State getState() | 返回该线程的名称 |
public String getName()/getPriorit() | 返回线程的名称和和优先级 |
public String setName()/setPriorit() | 设置线程的名称和优先级 |
线程的调度
线程的睡眠 Thread.sleep(long millis) throws InterruptedExceptions
millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。静态方法。
线程的加入(join)
join() throws InterruptedException方法,在该线程中调用另一个线程的join()方法,则当前线程转入Waiting线程,直到另一个线程运行结束,当前线程再由阻塞转为就绪状态。
yield() 暂停当前正在执行的线程对象。把机会执行让给相同(包括他自己)或者更高优先级的线程,该线程是静态方法,调用该方法之后,只是使该线程暂停停一下,不会阻塞该线程,而是使该线程直接进入就绪状态。则与该线程优先级相同或者更高的线程有可能获得执行机会。完全有可能,该线程暂停之后又马上获得执行机会。
线程的终止,stop方法已经被抛弃,提示,可以自定义一个标志量,然后提供一个方法,使其可以改变标志量的状态,可以停止线程。
线程的生命周期:
每个java程序都有一个缺省的主线程,对于java应用程序,主线程是main()方法执行的线索。要想实现多线程,必须在主线程中创建新的线程对象。任何线程在其生命周期中一般有5个状态,即创建,运行,阻塞,终止。线程状态的转移与方法之间的关系可以用下图表示:
守护线程(后台线程)
在后台运行,是为其他的线程提供服务,这种线程被称为"后台线程(Daemon Thread)",又称为"守护线程",JVM的垃圾回收线程就是典型的后台线程。
特征: 如果所有的前台线程都死亡,后台线程会自动死亡。
调用Thread 对象setDaemon(true)方法可讲指定线程设置成后台线程。这个方法的调用必须在start()方法之前。在线程中产生的新线程也是Daemon线程。