进程和线程
进程和线程的概念
现在的电脑手机,都能宏观
(现在的多核处理器能在真正意义上
实现这样的并行处理;但是我们的进程数是不会受处理器核数的影响的
,可以比处理器的核心数多,那时候还是要进行时间片的分配
,也就是宏观的实现并行处理)的在同一个时刻
做多个事情
(比如说,边写博客边听歌呀!)。这是因为有多进程
,才能让我们这么方便的做这些事情。简单的说:一个应用程序就可以看作是一个进程(当然会有一个应用有多个进程的情况)。
而一个进程(可以直接想象成一个应用程序)能够同时执行多个任务是由多线程来进行实现的(举个栗子:一个音乐播放器可以同时进行听歌和下载歌曲)。
进程和线程的区别
本质的区别在于一个进程
拥有自己的一整套变量
,而线程
是数据共享
的。
由于线程是共享变量的,因此线程之间的通信比进程之间的通信更有效、更容易。
一般的操作系统中,线程比进程更加的轻量,创建、撤销一个线程比启动新进程的开销小得多。
Java中多线程的实现
Java多线程实现的两种方式
通过自己写一个继承自Thread类的线程类。例如下面这样:
class MyThread extends Thread {
private int num = 5;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (num > 0) {
System.out.println("ThreadId is:" + Thread.currentThread().getId() + ",num is " + num--);
}
}
}
}
public class Test {
public static void main(String[] args) {
new MyThread().start();
new MyThread().start();
}
}
通过自己写一个实现了Runnable接口的Runnable类。例如下面这样:
class MyRunnable implements Runnable {
private int num = 5;
public void run() {
for (int i = 0; i < 10; i++) {
if (num > 0) {
System.out.println("ThreadId is:" + Thread.currentThread().getId() + " ,num is " + num--);
}
}
}
}
public class Test {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
new Thread(runnable).start();
new Thread(runnable).start();
}
}
PS:不要调用Thread类或者Runnable对象的run方法。直接调用run方法,只会执行同一个线程中的任务,而不会启动新线程。
两种实现多线程方式的区别
通过实现Runnable接口的方式,可以让多个线程共享一个变量。而通过继承Thread类的方式不行。上面两个方式得到的结果如下:
PS:通过继承Thread类的方式是不推荐的。因为我们应该将要并行运行的任务与运行机制解耦合。
线程的中断
线程中断的两种情况
- 当线程的run方法执行方法体中最后一句后,并经由执行return语句返回时。
- 出现了在方法体中没有捕获的异常时,线程将终止。PS:早期的Java版本中,有一个stop方法就是通过抛出ThreadDeath错误对象,由此杀死线程。但是这方法已经过时了,
不要在代码中调用
线程中断的实现
- 我们一般的线程中断是通过interrupt()和isInterrupted()两个方法结合来进行中断的。
- 每个线程都有一个boolean变量用来标志一个线程是否被中断。interrupt()调用后此变量就为true。
- 就像下面一样:
public class Test{
public static void main(String[] args) throws InterruptedException {
Runnable runnable = ()->{
while (!Thread.currentThread().isInterrupted());
};
Thread thread = new Thread(runnable);
thread.start();
System.out.println(thread.isInterrupted());
thread.interrupt();
System.out.println(thread.isInterrupted());
}
}
线程的六大状态
- New(新创建)
- 当
用new操作符创建一个新线程时
,如new Thread(r)。此时线程处于New状态
。
- 当
- Runnable(可运行)
- 一旦
调用start方法后,线程就处于Runnable状态(PS:一个可运行的线程可能正在运行也可能没有运行,这取决于操作系统给线程提供的运行时间)
。
- 一旦
- Blocked(被阻塞)、Waiting(等待)和Timed waiting(计时等待)
- 当一个线程试图获取一个内部的对象锁(不是java.util.concurrent库中的锁),而该锁被其他线程持有,则该线程处于
Block状态
。 - 当线程等待另一个线程通知调度器一个条件时,它自己进入
Waiting状态
。 - 当Thread.sleep、Object.wait、Thread.join、Lock.tryLock以及Condition.await的计时版方法被调用时,线程处于
Timed waiting状态
。
- 当一个线程试图获取一个内部的对象锁(不是java.util.concurrent库中的锁),而该锁被其他线程持有,则该线程处于
- Terminated(被终止)
- 因为run方法正常退出而自然死亡。
- 因为一个没有捕获的异常终止run方法而意外死亡。
线程的属性
线程优先级
- 在默认的情况下,
一个线程继承它的父类的优先级
。 - 线程的优先级可以是
MIN_PRIORITY(Thread类中定义为1)**与**MAX_PRIORITY(定义为10)
之间的任意值。其中还有一个NORM_PRIORITY(在Thread类中定义为5)
常量。 - 但是,
线程的优先级是高度依赖于系统的
。当虚拟机依赖于宿主机平台的线程实现机制,Java线程的优先级映射到宿主机平台的优先级上
,优先级的个数可能变多也可能变少。
守护线程
- 线程对象通过调用
setDaemon(true)
方法将其设置为守护线程。 - 守护线程的作用是为其它的线程提供服务。
当程序中只有守护线程的时候,虚拟机就会退出
。 - 由于守护线程的这个特点,
因此守护线程应该永远不要去访问固有资源
,如文件、数据库。
参考
- Java核心技术 卷一
总结
- 上面是对线程基本知识的介绍,也没啥好总结的。后面的内容继续介绍线程更深的东西。敬请期待~
转载请注明链接