JAVA全栈开发 day12-多线程入门

一、多线程入门

1.线程和进程

  • 进程

    进程:是指一个内存中运行的应用程序每个进程都有一个独立的内存空间和系统资源,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。进程是系统进行资源分配和调度的独立单位。

    单cpu同一时间点只能执行一件事情,CPU高效的切换让我们觉得是同时进行的

    我们在同一个进程内可以执行多个任务,每个任务就可以看成一个线程

    案例:
    百度云盘(一个应用程序:进程)
    下载功能(可以同时下载多个文件)

进程就是正在运行的程序
进程是系统进行资源分配和调度的独立单位,每一个进程都有它自己的内存空间和系统资源。

  • 线程

    线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

    简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程

    在同一个进程内可以执行多个任务,而这个每个任务就是看成线程

线程是程序执行的单元,执行路径,是程序使用cpu最基本单位。

cpu 只有一个, 每次只能执行一个(线程)

一个进程有多个线程

单线程 :如果程序只有只有一条执行路径 多线程:如果程序有多条执行路径

2.并行与并发

  • 并发 逻辑上同时发生,指再某一个时间同时运行的程序
  • 并行 物理上同时发生,指在某一个时间同时运行的程序

JAVA全栈开发 day12-多线程入门_第1张图片

3.多线程的意义

多线程存在的意义:不是提高程序的执行速率,其实是为了提高程序的使用率。
程序的执行其实都是在抢cpu的资源,cpu的执行权。
多个线程抢夺到cpu执行权的概率更大 线程抢夺执行权具有随机性

4.java程序的运行原理

由java命令启动jvm,启动jvm相当于启动了一个进程

接着该进程创建主线程(main)去调用main方法

jvm虚拟机的启动是单线程的还是多线程的?多线程

原因是垃圾回收线程也要启动,不然很容易就内存溢出

二、Thread的基本使用

1.创建线程的步骤

  1. 自定义一个类MyThread 继承Thread类
  2. 重写run方法
  3. 创建一个MyThread对象
  4. MyThread对象.start()
//1. 自定义一个类MyThread 继承Thread类
class MyThread extends Thread {
    public MyThread(String name) {
        super(name);
    }
//2. 重写run方法
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            // Thread.yield(); //让出cpu 使用权
//            try {
//                Thread.sleep(1000);//睡眠
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
            System.out.println(getName() + "我是最棒的:" + i);
        }
    }
}

public class Demo1 {
    public static void main(String[] args) {
//3. 创建一个MyThread对象
       MyThread t1 = new MyThread("t1");
       MyThread t2 = new MyThread("t2");
//4. MyThread对象.start()
       t1.start();
       t2.start();
        for(int i=0;i<10;i++){//主线程
            System.out.println(Thread.currentThread().getName()+"我是最棒的:"+i);
        }
    }
}


注: run 与 start 的区别

  1. 直接调用run方法相同与main线程在调用
  2. start() , jvm会创建一个新线程,然后jvm会自动运行线程的run方法

创建对个线程的方法

注:new 多个MyThread对象即可。不是要理解成调用多次start了

MyThread myThread = new MyThread(“张三”); //这就是一个线程

MyThread myThread2 = new MyThread(“李四”);

myThread.start();

myThread2.start();

获得线程的名字

String getName()
返回该线程的名称。

可以在Thread的子类中直接使用

Thread.currentThread() : 得到当前线程对象

System.out.println(Thread.currentThread().getName());

2.多线程独立栈空间

JAVA全栈开发 day12-多线程入门_第2张图片

3.多线程的打印具有随机性

JAVA全栈开发 day12-多线程入门_第3张图片

4.线程的调度

  • 分时调度:所有线程轮流使用CPU 的使用权,平均分配每个线程占用 CPU 的时间。

  • 抢占式调度:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的是抢占式调度。

设置线程的优先级:

  • 抢占式调度详解:大部分操作系统都支持多进程并发运行,现在的操作系统几乎都支持同时运行多个程序。比如:现在我 们上课一边使用eclipse编辑器,一边使用录屏软件,同时还开着画图板,dos窗口等软件。此时,这些程序是 在同时运行,”感觉这些软件好像在同一时刻运行着“。 实际上,CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是 在同一时刻运行。 其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的使用率更高。

JAVA全栈开发 day12-多线程入门_第4张图片

线程优化级高,并不能让线程先执行。它还是随机的,只是概率高点

  • 多线程好处:

    充分利用CPU的资源(多进程), 多线程(为当前程序抢占CPU使用权)

    简化编程模型

    带来良好的用户体验

    多个线程之间互不干扰

三、线程的控制

1.Thread类API

属性:

​ NORM_PRIORITY : 值为 5

​ MAX_PRIORITY : 值为 10

​ MIN_PRIORITY : 值为 1

构造方法:

Thread() :分配一个新的 Thread对象。。

Thread(String name) :分配一个指定名字的新的线程对象。

Thread(Runnable target) :分配一个带有指定目标新的线程对象。

Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。

常用方法:

String getName() :获取当前线程名称。

static Thread currentThread() :返回对当前正在执行的线程对象的引用。

void setName(String name) :将此线程的名称更改为等于参数 name 。

void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。

void run() :此线程要执行的任务在此处定义代码。

static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。

int getPriority() :返回此线程的优先级。

void setPriority(int newPriority) :更改此线程的优先级。

void join() :等待这个线程死亡。

static void yield() :对调度程序的一个暗示,即当前线程愿意让出当前使用的处理器。

void interrupt() :中断这个线程。

boolean isAlive() :测试这个线程是否活着。

Thread.State getState() :返回此线程的状态。

2.线程的休眠

public void run() {
        // 放让线程执行代码块
        for(int i=0;i<10;i++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(getName()+"我是最棒的:"+i);
        }
    }

3.线程的加入

void join() :等待这个线程死亡。

   MyThread myThread = new MyThread("张三"); //这就是一个线程
        MyThread myThread2 = new MyThread("李四");
        myThread.start();
        try {
            myThread.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        myThread2.start();

4.线程的礼让

static void yield() :对调度程序的一个暗示,即当前线程愿意让出当前使用的处理器。

 public void run() {
        // 放让线程执行代码块
        for(int i=0;i<10;i++){
            Thread.yield(); //让出cpu 使用权
            System.out.println(getName()+"我是最棒的:"+i);
        }
    }

5.线程的中断

public final void stop (): 让线程停止,过时了,但是还可以使用。
public void interrupt ( )∶中断线程。把线程的状态终止,并抛出一个InterruptedException.

6.线程的守护

public final void setDaemon(boolean on)

将此线程标记为daemon线程或用户线程。当运行的唯一线程都是守护进程线程时,Java虚拟机将退出。

线程启动前必须调用此方法。

JAVA全栈开发 day12-多线程入门_第5张图片

 MyThread myThread = new MyThread("张三"); //这就是一个线程
        MyThread myThread2 = new MyThread("李四");
        myThread.setDaemon(true);
        myThread2.setDaemon(true);
        myThread.start();
        myThread2.start();
//        myThread.interrupt();

        for(int i=0;i<10;i++){

            System.out.println(Thread.currentThread().getName()+"我是最棒的:"+i);
        }

四、Runnable创建多线程

runable方式创建线程

  1. 创建一个Runable接口的实现类MyRunable
  2. 重写run方法
  3. 创建实现类MyRunable对象, myrunable
  4. 创建Thread类的对象,把 myrunable对象作为构造参数传过去
//1. 创建一个Runable接口的实现类MyRunable
class MyRunabled implements Runnable {
//2. 重写run方法
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + ":我是最棒的" + i);
        }
    }
}

public class Demo2 {
    public static void main(String[] args) {
//3. 创建实现类MyRunable对象, myrunable
        MyRunabled myRunabled = new MyRunabled();
//4. 创建Thread类的对象,把 myrunable对象作为构造参数传过去
        Thread t3 = new Thread(myRunabled,"t3");
        Thread t4 = new Thread(myRunabled,"t4");
        t3.start();
        t4.start();
        for(int i=0;i<10;i++){//主线程
            System.out.println(Thread.currentThread().getName()+"我是最棒的:"+i);
        }
    }
}


五、创建多线程方式总结

实现多线程方式:两种

  • 方法1:Thread类

    1. 自定义一个MyThread类继承Thread类
    2. 在MyThread类中重写run方法
    3. 创建MyThread类的对象
    4. 启动线程对象。start()方法
  • 方法2:Runable 接口

    1. 定义一个Runable接口的实现类,MyRunable类
    2. 在MyRunable类中重写run方法
    3. 创建MyRunable类的对象myRunable
    4. 创建Thread类的对象,且将myRunable对象作构造方法的参数传递
    5. 启动线程 . start方法

问题:为什么有了方法1,还需要方法2

  1. 为了避免 java 中由于单继承带来的局限性
  2. runable接口实现的线程,适合多个相同的代码去处理同一个资源的情况,把线程的同程序的代码,数据进行有效分享,体现了面向对象思想

线程安全问题

卖票Thread实现

卖票Runable实现

出现同票原因

// 分析同票的原因
// 线程抢夺cpu 执行权时,执行的代码具有原子性
// 原子性是指最基本的代码(最小的语句)

出现负票的原因

如何解决

  • IllegalArgumentException
    

你可能感兴趣的:(JAVA全栈开发学习,java,开发语言,linux)