文章目录
一、什么是进程?
狭义的讲,进程(Process)就是正在运行的程序的实例。或者说进程就是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,它是操作系统动态执行的基本单元。多道程序系统出现后,为了刻画系统内部出现的动态情况,描述系统内部各道程序的活动规律而引进了进程概念。从理论角度看,是对正在运行的程序过程的抽象;从实现角度看,是一种数据结构,目的在于清晰地刻画动态系统的内在规律,有效管理和调度进入计算机主存运行的程序。进程由程序、数据和进程控制块三部分组成,具有以下几个特征:
- 动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
- 并发性:任何进程都可以同其他进程一起并发执行
- 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;
- 异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进
进程执行时的间断性,决定了进程可能具有多种状态。事实上,运行中的进程可能具有以下三种基本状态。
1)就绪状态(Ready):
进程已获得除处理器外的所需资源,等待分配处理器资源;只要分配了处理器进程就可执行。就绪进程可以按多个优先级来划分队列。例如,当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列;当进程由I/O操作完成而进入就绪状态时,排入高优先级队列。
2)运行状态(Running):
进程占用处理器资源;处于此状态的进程的数目小于等于处理器的数目。在没有其他进程可以执行时(如所有进程都在阻塞状态),通常会自动执行系统的空闲进程。
3)阻塞状态(Blocked):
由于进程等待某种条件(如I/O操作或进程同步),在条件满足之前无法继续执行。该事件发生前即使把处理器资源分配给该进程,也无法运行。
二、进程与程序的区别?
程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。而进程是程序在处理机上的一次执行过程,它是一个动态的概念。程序可以作为一种软件资料长期存在,而进程是有一定生命期的。程序是永久的,进程是暂时的。进程更能真实地描述并发,而程序不能;进程是由进程控制块、程序段、数据段三部分组成;进程具有创建其他进程的功能,而程序没有。同一程序同时运行于若干个数据集合上,它将属于若干个不同的进程,也就是说同一程序可以对应多个进程。
三、什么是线程?
线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
线程具有以下特性:
- 轻型实体 。线程中的实体基本上不拥有系统资源,只是有一点必不可少的、能保证独立运行的资源。
线程的实体包括程序、数据和TCB。线程也是动态概念,它的动态特性由线程控制块TCB(Thread Control Block)描述。TCB包括以下信息:
(1)线程状态。
(2)当线程不运行时,被保存的现场资源。
(3)一组执行堆栈。
(4)存放每个线程的局部变量主存区。
(5)访问同一个进程中的主存和其它资源。
(6)用于指示被执行指令序列的程序计数器、保留局部变量、少数状态参数和返回地址等的一组寄存器和堆栈。 - 共享进程资源。在同一进程中的各个线程,都可以共享该进程所拥有的资源,这首先表现在:所有线程都具有相同的地址空间(进程的地址空间),这意味着,线程可以访问该地址空间的每一个虚地址;此外,还可以访问进程所拥有的已打开文件、定时器、信号量机构等。由于同一个进程内的线程共享内存和文件,所以线程之间互相通信不必调用内核。
- 并发执行。在一个进程中的多个线程之间,可以并发执行。
线程由哪些部分组成?或者说,线程应该包含哪些信息?
第一, 指令集。线程首先本质上也是一个指令集。通过这个指令集,来告诉CPU自己要做的事情。
第二, 栈。我们知道,当线程数量大于逻辑CPU数量时,逻辑CPU会以时间分片的形式去完成多线程。也就是说,每个线程都可能经过若干阻塞-就绪-运行的过程。那么,在阻塞时,就需要将线程当前的执行现场进行保存,以备在运行时,恢复现场。现场一般包含当前程序执行的位置,局部变量等等。也就是说,当一个线程创建时,就应该有一个专属空间,用于存放线程的相关信息。这块内存空间,称之为栈。
第三, 工作内存。以JVM来说,多个线程共享一块主内存,每个线程又有自己独立的工作内存。
线程的状态:
四、线程与进程的区别?
- 进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
- 线程上下文切换比进程上下文切换要快得多。
- 线程间可以直接读写进程数据段(如全局变量)来进行通,需要进程同步和互斥手段的辅助,以保证数据的一致性。而进程间通信(IPC),可以通过如:管道、 消息队列、 信号量、 共享内存、 网络Socket等。
五、多线程的优点与缺点
优点
多个线程并行执行,可以充分利用CPU的资源;
缺点
线程数量不是越多越好,线程的创建切换和销毁都需要时间和空间资源,线程过多可能会造成OOM(out of memory),还有就是死锁问题
六、java 创建线程的方式
1.继承Thread类
public class ThreadTest extends Thread {
String name;
int step=0;
public ThreadTest(String name) {
this.name = name;
}
@Override
public void run() {
while (true){
System.out.println(name+":"+step);
if(step>=10){
System.out.println(name+",over");
break;
}
if("rabbit".equals(name)){
step+=3;
try {
if(step>5){
sleep(1);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}else if("tortoise".equals(name)){
step++;
}
}
}
public static void main(String[] args) {
ThreadTest test1 = new ThreadTest("rabbit");
ThreadTest test2 = new ThreadTest("tortoise");
test1.start();
test2.start();
}
}
运行结果:
2.实现Runnable接口
class SellTicket implements Runnable {
private int num = 10;
@Override
public void run() {
while (true){
if(num>0){
num--;
System.out.println(Thread.currentThread().getName()+"卖出一张,剩余"+num+"张");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
System.out.println(Thread.currentThread().getName()+"余票为"+num+",停止售卖");
break;
}
}
}
public static void main(String[] args) {
SellTicket sellTicket = new SellTicket();
for(int i=1;i<=3;i++){
Thread thread =new Thread(sellTicket,"窗口"+i);
thread.start();
}
}
}
运行结果:
3.实现Callable接口
import java.util.concurrent.*;
public class ThreadCallabble implements Callable {
@Override
public Object call() throws Exception {
int i = 0;
for (; i < 10; i++) {
System.out.println("当前线程:" + Thread.currentThread() + ":" + i);
}
return i;
}
public static void main(String[] args) {
ThreadCallabble tc = new ThreadCallabble();
FutureTask<Object> fu = new FutureTask<>(tc);
Thread thread = new Thread(fu);
thread.start();
System.out.println("当前线程:" + Thread.currentThread());
}
}
运行结果:
4.线程池
方式 |
---|
Executors.newFixedThreadPool() |
Executors.newCachedThreadPool() |
Executors.newScheduledThreadPool() |
new ThreadPoolExecutor() |
public static void test01(){
ExecutorService executorService = Executors.newFixedThreadPool(8);
for(int i=0;i<10;i++){
executorService.submit(()->{
System.out.println("thread is is:"+Thread.currentThread().getId());
try{
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
public static void createCachedThredPool(){
ExecutorService executorService = Executors.newCachedThreadPool();
final CountDownLatch downLatch = new CountDownLatch(10);
for(int i=0;i<10;i++){
final int curIndex = i;
executorService.execute(()->{
System.out.println(Thread.currentThread().getName()+",curIndex is:"+curIndex);
downLatch.countDown();
});
}
try {
downLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("全部线程执行完毕");
}
public static void createSchduledThredPool(){
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
//定时调度1,每个任务至少等待'period'的时间
//如果任务的执行时间超过period,则等待的时间为执行的时间
executorService.scheduleAtFixedRate(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
},0,2,TimeUnit.SECONDS);
//定时调度2,第二个任务执行的时间为 = 第一个任务执行的时间+'delay'
executorService.scheduleWithFixedDelay(()->{
try {
Thread.sleep(5000);
System.out.println(System.currentTimeMillis()/1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
},0,2,TimeUnit.SECONDS);
//定时调度,延迟’delay'后执行,并且只执行一次
executorService.schedule(()->{
System.out.println("5秒后执行schedule");
},5,TimeUnit.SECONDS);
}
private static void testExecutotMethods() {
ExecutorService executorService = new ThreadPoolExecutor(1,1,1,TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1)){
@Override
protected void beforeExecute(Thread t, Runnable r) {
System.out.println("beforeExecute is called");
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
System.out.println("afterExecute is called");
}
@Override
protected void terminated() {
System.out.println("terminated is called");
}
};
executorService.submit(()->{
System.out.println("this is a tesk");
});
executorService.shutdown();
}
暂时先写到这吧,啊啊,后续完善修改