首先,从操作系统的层次来说,进程(Progress)是资源分配和系统调度的的基本单位也可以理解为程序的基本执行实体;当一个程序被载入到内存中并准备执行,它就是一个进程!当进程被创建了,操作系统就会为该进程分配一个唯一、不重复的 ID,用于区分不同的进程
线程(Thread)是 CPU 调度的最小单位,是程序执行流的最小单位,线程不能独立的拥有资源(应该由多个线程共享),创建线程的开销要比进程小很多,因为创建线程仅仅需要堆栈指针
和程序计数器
就可以了,而创建进程需要操作系统分配新的地址空间,数据资源等,这个开销比较大。每一个进程(程序)都至少有一个线程,进程是线程的容器,在单个程序中同时运行多个线程完成不同的工作,称为多线程!
进程和线程的区别可以归纳为以下的几点
在一般的操作系统中,用户使用的进程,如:QQ、音乐、浏览器等,这些用户进程数一般是多于 CPU 核数,这将导致它们在运行的过程中相互争夺 CPU,这就要求操作系统有一定策略来分配进程。一般的有如下的五种常用的进程调度算法
先来先服务 (FCFS) 调度算法是一种最简单的调度算法,该算法既可用于作业调度,也可用于进程调度。当在作业调度中采用该算法时,每次调度都是从后备作业队列中选择一个或多个最先进入该队列的作业,将它们调入内存,为它们分配资源、创建进程,然后放入就绪队列。在进程调度中采用 FCFS 算法时,则每次调度是从就绪队列中选择一个最先进入该队列的进程,为之分配处理机,使之投入运行。该进程一直运行到完成或发生某事件而阻塞后才放弃处理机。
短作业 (进程) 优先调度算法,是指对短作业或短进程优先调度的算法。它们可以分别用于作业调度和进程调度。短作业优先 (SJF) 的调度算法是从后备队列中选择一个或若干个估计运行时间最短的作业,将它们调入内存运行。而短进程优先 (SPF) 调度算法则是从就绪队列中选出一个估计运行时间最短的进程,将处理机分配给它,使它立即执行并一直执行到完成,或发生某事件而被阻塞放弃处理机时再重新调度。
系统将所有的就绪进程按先来先服务的原则排成一个队列,每次调度时,把 CPU 分配给队首进程,并令其执行一个时间片。时间片的大小从几 ms 到几百 ms。当执行的时间片用完时,由一个计时器发出时钟中断请求,调度程序便据此信号来停止该进程的执行,并将它送往就绪队列的末尾;然后,再把处理机分配给就绪队列中新的队首进程,同时也让它执行一个时间片。这样就可以保证就绪队列中的所有进程在一给定的时间内均能获得一时间片的处理机执行时间。换言之,系统能在给定的时间内响应所有用户的请求。
多级反馈队列调度算法则不必事先知道各种进程所需的执行时间,而且还可以满足各种类型进程的需要,因而它是目前被公认的一种较好的进程调度算法。在采用多级反馈队列调度算法的系统中,调度算法的实施过程如下所述: 1)应设置多个就绪队列,并为各个队列赋予不同的优先级。第一个队列的优先级最高,第二个队列次之,其余各队列的优先权逐个降低。该算法赋予各个队列中进程执行时间片的大小也各不相同,在优先权愈高的队列中,为每个进程所规定的执行时间片就愈小。例如,第二个队列的时间片要比第一个队列的时间片长一倍,第 i+1 个队列的时间片要比第 i 个队列的时间片长一倍。 2)当一个新进程进入内存后,首先将它放入第一队列的末尾,按 FCFS 原则排队等待调度。当轮到该进程执行时,如它能在该时间片内完成,便可准备撤离系统;如果它在一个时间片结束时尚未完成,调度程序便将该进程转入第二队列的末尾,再同样地按 FCFS 原则等待调度执行;如果它在第二队列中运行一个时间片后仍未完成,再依次将它放入第三队列,……,如此下去,当一个长作业 (进程) 从第一队列依次降到第 n 队列后,在第 n 队列便采取按时间片轮转的方式运行。 3)仅当第一队列空闲时,调度程序才调度第二队列中的进程运行;仅当第 1~(i-1) 队列均空时,才会调度第 i 队列中的进程运行。如果处理机正在第 i 队列中为某进程服务时,又有新进程进入优先权较高的队列 (第 1~(i-1) 中的任何一个队列),则此时新进程将抢占正在运行进程的处理机,即第 i 队列中某个正在运行的进程的时间片用完后,由调度程序选择优先权较高的队列中的那一个进程,把处理机分配给它。
此算法常被用于批处理系统中,作为作业调度算法,也作为多种操作系统中的进程调度算法,还可用于实时系统中。当把该算法用于作业调度时,系统将从后备队列中选择若干个优先权最高的作业装入内存。当用于进程调度时,该算法是把处理机分配给就绪队列中优先权最高的进程,这时,又可进一步把该算法分成如下两种。
在一个 Java 程序中默认有几个线程?
2 个,一个 main
函数运行起来,这个 main 函数中是一个单线程程序!但是这个所谓的单线程程序只是 JVM
这个程序中的一个线程,JVM 本身是一个多线程的程序,除了这个主函数,还有 GC
线程(垃圾收集器线程)
public class Test {
public static void main(String[] args) {
Thread thread = new Thread();
thread.start();
}
}
上面是一个线程开启的实例代码,那 Java 真的能开启多线程吗?查看这个 start()
方法的实现!如下:
start()
方法是通过调用方法本地 start0()
从而开启多线程的,其原理还是调用了 C++ 的方法从而开启一个线程,Java 是无法直接调用硬件的!
线程的一个 getState()
能返回一个 State
的枚举类型如下:
public enum State {
NEW, // 新生
RUNNABLE, // 运行
BLOCKED, // 阻塞
WAITING, // 等待
TIMED_WAITING,// 超时等待
TERMINATED; // 终止
}
即 Java 有如上的几种状态。
虽然 wait 和 sleep 都能将线程状态变成等待状态,但是它们在行为和使用方式上完全不一样的。
wait()
必须在正在同步代码块中使用,如 synchronized
或 Lock
中使用;而 sleep()
方法不需要再同步条件下调用,你可以任意正常的使用。
wait()
方法用于和定义于 Object
类的,而 sleep
方法操作于当前线程,定义在 java.lang.Thread
类里面。
调用 wait()
的时候方法会释放当前持有的锁,而 sleep
方法不会释放任何锁(抱着锁睡觉)
public class Test {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
System.out.println("new thread");
}
}
通过继承 Thread 类,并重写它的 run 方法,我们就可以创建一个线程。
public class Test {
public static void main(String[] args) {
MyThread thread =new MyThread();
new Thread(thread).start();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println("new Thread");
}
}
通过实现 Runnable ,并实现 run 方法,也可以创建一个线程。
上面的代码并不是很好,这样会降低线程类的耦合性,可以使用如下的 Lambda
表达式创建线程(推荐使用)
public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread thread = new Thread(() -> { // 这里使用lambda表达式
myThread.print();
});
thread.start();
}
}
class MyThread {
public void print() {
System.out.println("我是线程类");
}
}
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> task = new FutureTask<>(new MyThread());
new Thread(task).start();
Integer result = task.get(); // 获取线程的指向结果,阻塞式
System.out.println(result);
}
}
class MyThread implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return new Random().nextInt(100);
}
}
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i=0;i<10;i++){
executorService.execute(new MyThread());
}
executorService.shutdown();
}
}
class MyThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"=>执行了");
}
}
此处用 JDK 自带的 Executors 来创建线程池对象。
前者是逻辑上的同时发生,而后者是物理上的同时发生
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。