Java基础学习总结:多线程之(一)并发和并行,线程和进程,线程的三种创建方式,Runnable 和 Callable 的区别

1、并发和并行

并行(parallellism):

指两个或多个事件在同一时刻发生;

在同一时刻,有多条指令在多个处理器上同时执行,无论从微观还是从宏观来看,指令都是一起执行的。

并发(concurrency):

是指两个或多个事件在同一时间间隔发生;

指同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得宏观上具有多个进程同时执行的效果,但微观上并不是同时执行的,只是按时间片轮换策略快速的交替执行。 

2、进程和线程

(1)什么是进程

进程是一个正在运行的程序,是一个程序的运行状态和资源占用(内存,CPU)的描述,通过进程ID区分。 进程是程序的一个动态过程,它指的是从代码加载到执行完毕的一个完成过程。 目前操作系统支持多进程多任务。

进程的特点:

  1. 独立性:不同的进程之间是独立的,相互之间资源不共享(举例:两个正在上课的教室有各自的财 产,相互之间不共享)
  2. 动态性:进程在系统中不是静止不动的,而是在系统中一直活动的
  3. 并发性:多个进程可以在单个处理器上同时进行,且互不影响

(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();
    }
}

 

上一篇:java比较相等符


下一篇:创建线程任务