基础知识(小故事)

1、计算机的核心是CPU,他承担了所有计算任务,他就想一个工厂,时刻在运行。

2、假设工厂电力有限,一次只能提供给一个车间使用,也就是说,一个车间开工的时候,其他车间必须要停工。背后的含义就是,单个CPU一次只能运行一个任务。

3、进程就好比工厂的车间,他代表CPU所能处理的单个任务,任意时刻CPU总是运行一个进程,其他的进程处于非运行状态。

4、一个车间里,可以有很多工人他们协同完成一个任务。

5、线程就好比工厂的工人,一个进程可以包括多个线程。

6、车间的空间是工人共性的,比如许多房间是每个工人都可以进出的,这个象征一个进程的内存空间是共享,每个线程都可以使用这些共享内存。

7、可是每间房间的大小不同,有些房间做多只能容纳一个,比如厕所,里面有的时候,其他人就不能进去了,这代表一个线程使用默写共享内存是,其他线程必须等他结束,才能使用这一个块内存。

8、防止其他人进入的简单办法就是给门口加上一把锁,先到的人关门上锁,后到的人看到上锁了,就在门口排队,等待门打开再进去,这就是互斥锁(Mutex),防止多个线程同时读写某一块内存区域。

9、这些房间,可以同时容纳N个人,比如厨房,也就说,如果人数大于N,多出来的人只能在外面等着,这好比某些内存区域,只能提供拱顶数目的线程使用!

10、这个时候解决办法,就是在门口挂N把锁,进入的人就取一把锁,出来的时候在把锁挂回去,后来的人发现钥匙没有了,就知道必须门口排队了,这种叫做信号量。用来保证多线程不会相互冲突。

11、操作系统的设计,因此可以归结为三点: (1)以多进程形式,允许多个任务同时运行。

(2) 以多个线程形式,允许单个任务分成不同的部分运行。

(3) 提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。

什么是进程

计算机程序的执行,就是进程

进程的状态

1、新生 进程的心产生中。 2、运行 正在运行。 3、等待 等待某事发生,例如等待用户输入完成,有的也成为了阻塞。 4、就绪 排版中,等待CPU。 5、结束 完成运行。

注意:进程的格子上状态之间是不能随意切换的,例如当进程运行时因为IO操作而阻塞,当IO操作完成后,并不会直接回复运行状态,而是转为就与状态CPU的调度。

什么是线程

操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。

为什么用多线程

避免阻塞,单个县城中的程序是顺序执行的,如果前面的操作发生了阻塞,那么会影响到后面的操作。这个时候可以采用多线程。

线程比进程的优点

1、避免阻塞,异步调用。

2、避免CPU空转,例如HTPP响应,处理完一条在处理下一条存在大量空余时间。

3、提升性能,减少损耗,多线程消耗在一定条件下是小于进程之间的切换。

java如何使用多线程

继承Thread

重写run方法:使用继承方式的好处是,在run()方法内获取当前线程直接使用this就可以了,无须使用Thread.currentThread()方法;不好的地方是Java不支持多继承,如果继承了Thread类,那么就不能再继承其他类。另外任务与代码没有分离,当多个线程执行一样的任务时需要多份任务代码。

package com.haojishu.until;

public class MyThread extends Thread {
  @Override
  public void run() {
    // 编写代码,这段程序在分支线程中执行
    for (int i = 0; i < 100; i++) {
      System.out.println("分支线程--->" + i);
    }
  }
}

package com.haojishu;

import com.haojishu.until.MyThread;

public class Me {

  public static void main(String[] args) {
    MyThread myThread = new MyThread();
    myThread.start();
    for (int i = 0; i < 100; i++) {
      System.out.println("主线程打印: " + i);
    }
  }
}

实现Runable接口

实现run方法:解决继承Thread的缺点,没有返回值

package com.haojishu.until;

public class RunableTest implements Runnable {
  @Override
  public void run() {
    // 编写代码,这段程序在分支线程中执行
    for (int i = 0; i < 100; i++) {
      System.out.println("分支线程--->" + i);
    }
  }
}

package com.haojishu;

import com.haojishu.until.RunableTest;

public class Me {

  public static void main(String[] args) {
    RunableTest runableTest = new RunableTest();
    new Thread(runableTest).start();
    for (int i = 0; i < 100; i++) {
      System.out.println("主线程打印: " + i);
    }
  }
}

实现Callable接口

使用继承方式的好处是方便传参,你可以在子类里面添加成员变量,通过set方法设置参数或者通过构造函数进行传递,而如果使用Runnable方式,则只能使用主线程里面被声明为final的变量。不好的地方是Java不支持多继承,如果继承了Thread类,那么子类不能再继承其他类,而Runable则没有这个限制。前两种方式都没办法拿到任务的返回结果,但是Callable方式可以

package com.haojishu.until;

import java.util.concurrent.Callable;

public class CallTest implements Callable {
  @Override
  public Object call() throws Exception {
    return "hahah";
  }
}

package com.haojishu;

import com.haojishu.until.CallTest;

import java.util.concurrent.FutureTask;

public class Me {
  public static void main(String[] args) {
    FutureTask<String> stringFutureTask = new FutureTask<String>(new CallTest());
    new Thread(stringFutureTask).start();
    try {
      String s = stringFutureTask.get();
      System.out.println(s);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}