Java多线程入门

一、概述

1.多线程和单线程

  • 单线程:若有多个任务,只有当上一个任务执行结束后,下一个任务才开始执行
  • 多线程:若有多个任务,可以同时执行,即一个程序中有多个线程在同时执行

2.调度方式

在操作系统中,有很多种调度方式,这里介绍分时调度和抢占式调度,在Java中使用的是抢占式调度

  • 分时调度:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间
  • 抢占式调度:每个线程都有其优先级,优先让优先级高的进程使用 CPU,如果线程优先级相同,则会随机选择去执行。
    (1) CPU 使用抢占式调度模式在多个线程间进行着高速的切换
    (2) 对于 CPU 的一个核而言,某个时刻只能执行一个线程,而 CPU 在多个线程间切换速度相对我们的感觉要快,看上去就是在同一时刻执行
    (3) 多线程程序并不能提高程序的运行速度,但能提高程序运行效率,让 CPU 的使用率更高

3. 主线程

Java程序在执行过程中,先启动 JVM,并加载对应的 class 文件,JVM 并会从 main 方法开始执行我们的程序代码,一直把 main 方法的代码执行结束。在 JVM 启动后,必然有一个执行路径(线程)从 main 方法开始,一直执行到 main 方法结束,这个线程在 Java 中称之为主线程。当程序的主线程执行时,如果遇到了循环而导致程序在指定位置停留时间过长,则无法马上执行下面的程序,需要等待循环结束后才能够执行,那么,能否实现一个主线程负责执行其中一个循环,再由另一个线程负责其他代码的执行,最终实现多部分代码同时执行的效果呢?办法总比困难多,多线程便孕育而生,很好的解决了这个问题!

二、线程的创建

创建新线程有两种方法:

  • 方法一:类声明为 Thread 的子类,该子类应重写 Thread 类的 run 方法,然后创建对象,开启线程
  • 方法二:声明一个实现 Runnable 接口的类,该类然后实现 run 方法,然后创建Runnable的子类对象,传入到某个线程的构造方法中,开启线程

1.方法一:继承Thread创建线程

(1)创建步骤
  • 定义一个类继承 Thread 类
  • 重写 run 方法
  • 创建子类对象,即创建线程对象
  • 调用 star 方法,开启线程并让线程执行,同时还会告诉 JVM 去调用 run 方法

自定义线程类:

public class myThread extends Thread {
    //重写run方法,完成该线程执行的逻辑
    public void run()
    {
        for(int i = 0;i < 50;i++)
        {
            System.out.println("新线程正在执行" + i);
        }
    }
}

在主线程中调用:

public static void main(String[] args)
{
    //创建自定义线程对象
    myThread mT = new myThread();
    //开启新线程,让新的线程执行程序,jvm调用线程中的run
    mT.start();
    //在main方法中执行
    for(int i = 0;i < 50;i++)
    {
        System.out.println("main线程正在执行" + i);
    }
}

分析:

  • 创建新的线程后,会产生两个执行路径,都会被CPU执行,CPU有自己的选择执行权力,所以会出现随机的执行结果
  • 注:线程对象调用 run 方法和调用 star 方法的区别:
    (1) 线程对象调用 run 方法不开启线程,仅仅是对象调用方法
    (2) 线程对象调用 star 方法开启线程,并让 JVM 调用 run 方法在开启的线程中执行
(2)多线程内存理解
  • 多线程在执行的时候,是在栈内存中的,每一个执行线程都有一片自己的所属栈内存空间,进行方法的压栈和出栈
  • 当执行线程的任务结束了,线程自动在栈内存中释放,当所有的执行线程都结束了,进程也就结束了
(3)获取和设置线程名称
  • String getName():返回该线程的名称(同Thread.currentThread().getName())
  • Thread.currentThread():获取当前线程对象
  • Thread.currentThread().getName():获取当前线程对象的名称
  • setName():设置线程名称
public static void main(String[] args)
{
    myThread mT = new myThread();
    mT.start();
    mT.setName("oneStar");    //设置线程名称
    //System.out.println(getName());  //使用getName()方法获取线程名称 在新线程中可以这样使用
    System.out.println(Thread.currentThread().getName());   //使用Thread.currentThread().getName()获取线程名称
    System.out.println(Thread.currentThread()); //获取当前线程对象
}
(4)Thread类sleep方法

sleep 方法是一个静态的方法,可以通过 Thread 类直接调用,会有异常抛出

public static void main(String[] args) {
    myThread mT = new myThread();
    mT.start();
    //使用sleep方法延时打印for循环
    for(int i = 0;i < 5;i++)
    {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(i);
    }
}

2.方法二:实现Runnable接口创建线程

Runnable 接口用来指定每一个线程要执行的任务,包含了一个 run 的无参数抽象方法,需要由接口实现重写该方法。此创建线程的方法是声明实现 Runnable 接口的类,该类实现 run 方法,然后创建 Runnable 的子类对象,传入到某个线程的构造方法中,开启线程

(1)创建步骤
  • 定义类实现 Runnable 接口
  • 重写接口中的 run 方法
  • 创建 Thread 类的方法
  • 将 Runnable 接口的子类对象作为参数传递给 Thread 类的构造函数
  • 调用 Thread 类的 star 方法开启线程

定义实现类接口

//定义实现类接口
public class myRunnable implements Runnable {
    //重写run方法
    public void run()
    {
        for(int i = 0;i < 5;i++)
        {
            System.out.println("myRunnable线程正在执行!");
        }
    }
}

在主线程中调用

public static void main(String[] args)
{
    //创建线程执行目标类对象
    myRunnable mR = new myRunnable();
    //将Runnable接口的子类对象作为参数传递给Thread类的构造函数
    Thread t1 = new Thread(mR);
    Thread t2 = new Thread(mR);
    //开启线程
    t1.start();
    t2.start();
    for(int i = 0;i < 5;i++)
    {
        System.out.println("main线程正在执行!");
    }
}
(2)实现Runnable接口的好处
  • 避免了单继承的局限性,所以此方法较为常用

三、线程的匿名内部类

使用线程的匿名内部类方式,可以方便的实现每个线程执行不同线程任务操作

方法一:重写 Thread 类中的方法创建线程

new Thread() {
    public void run() {
        for (int x = 0; x < 40; x++) {
            System.out.println(Thread.currentThread().getName()
                    + "...X...." + x);
        }
    }
}.start();

方法二:使用匿名内部类的方式实现 Runnable 接口,重写 Runnable 接口中的 run 方法

Runnable r = new Runnable() {
    public void run() {
        for (int x = 0; x < 40; x++) {
            System.out.println(Thread.currentThread().getName()
                    + "...Y...." + x);
        }
    }
};
new Thread(r).start();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值