1、并发和并行
并行(parallellism):
指两个或多个事件在同一时刻发生;
在同一时刻,有多条指令在多个处理器上同时执行,无论从微观还是从宏观来看,指令都是一起执行的。
并发(concurrency):
是指两个或多个事件在同一时间间隔发生;
指同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得宏观上具有多个进程同时执行的效果,但微观上并不是同时执行的,只是按时间片轮换策略快速的交替执行。
2、进程和线程
(1)什么是进程
进程是一个正在运行的程序,是一个程序的运行状态和资源占用(内存,CPU)的描述,通过进程ID区分。 进程是程序的一个动态过程,它指的是从代码加载到执行完毕的一个完成过程。 目前操作系统支持多进程多任务。
进程的特点:
- 独立性:不同的进程之间是独立的,相互之间资源不共享(举例:两个正在上课的教室有各自的财 产,相互之间不共享)
- 动态性:进程在系统中不是静止不动的,而是在系统中一直活动的
- 并发性:多个进程可以在单个处理器上同时进行,且互不影响
(2)什么是线程
线程就是一条执行路径。是进程的组成部分,一个进程可以有多个线程,每个线程去处理一个特定的子任务。
线程的特点:
线程的执行是抢占式的,多个线程在同一个进程中可以并发执行,其实就是CPU快速的在不同的线程之间切换,
也就是说,当前运行的线程在任何时候都有可能被挂起,以便另外一个线程可以运行
(3)线程和进程的区别
根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位;
开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间切换开销较大;线程可以看做是轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(cp),线程之间切换开销小;
所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程中有一个或多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行);
内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,处了CPU外,系统不会为线程分配内存(线程所有的资源来自其所属的进程的资源),线程组之间共享资源。
包含关系:进程是线程的容器,只有一个线程的进程是单线程程序;有多个线程非线性执行的进程是多线程程序;线程也被称为轻权进程或者轻量级进程。
3、线程的三种创建方式
(1)继承 Thread 类
package basis.StuThread.Ticket_0;
public class TestMyThread {
public static void main(String[] args) {
System.out.println("main 方法。。。");
//第二步,创建实例
MyThread_1 myThread_1 = new MyThread_1();
//开启线程
myThread_1.start();
}
}
//第一步:创建Thread的子类,重写run方法
class MyThread_1 extends Thread {
@Override
public void run() {
System.out.println("run 方法。。。");
}
}
(2)实现 Runnable 接口
package basis.StuThread.Ticket_0;
public class TestMyRunnable {
public static void main(String[] args) {
System.out.println("main 方法。。。");
//第二步,实例化一个Runnable的实现类
MyThread_2 myThread_2 = new MyThread_2();
//第三步,创建 Thread 对象,传入Runnable实现类的对象
Thread thread = new Thread(myThread_2);
//第四步,开启线程
thread.start();
}
}
//第一步创建Runnable的实现类,实现Runnable 接口的run方法
class MyThread_2 implements Runnable{
@Override
public void run() {
System.out.println("run 方法。。。");
}
}
(3)实现 Callable 接口
package basis.StuThread.Ticket_0;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class TestMyCallable {
public static void main(String[] args) {
System.out.println("main 方法。。。");
//第二步,创建Callable实例类对象
MyCallable<String> myCallable = new MyCallable<>();
//第三步,创建FutureTask任务
FutureTask<String> oneTask = new FutureTask<>(myCallable);
//第四步,由FutureTask<Integer>创建Thread对象
Thread oneThread = new Thread(oneTask);
//第五步,开启线程
oneThread.start();
}
}
//第一步,创建Callablej接口实现类,重写call()方法,支持泛型
class MyCallable<String> implements Callable {
@Override
public Object call() throws Exception {
System.out.println("call 方法。。。");
return "MyCall";
}
}
FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和 Runnable 接口。
4、Runnable 和 Callable 的区别
Runnable 和 Callable的区别:
- Callable 规定的方法是call(),Runnable 规定的方法是run();
- Callable() 任务执行后可返回值,而 Runnable 的任务是不能有返回值的;
- call() 方法可以抛出异常,run() 方法不可以;
- 运行 Callable 任务可以拿到一个 Future 对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过 Future 对象可以了解任务执行情况,可取消任务的执行,还可以获取执行结果。
5、卖票程序(无并发)
四个窗口,各卖100张票
window类
package basis.StuThread.Ticket_0;
public class Window extends Thread{
private int ticket = 100;
@Override
public void run() {
for (int i = 0;i<100;i++){
System.out.println(this.getName()+"卖了第"+ticket+"张票");
ticket--;
}
}
}
主类(测试类):
package basis.StuThread.Ticket_0;
public class Test {
public static void main(String[] args) {
new Window().start();
new Window().start();
new Window().start();
}
}