线程的基本概念 - 实现多线程的四种基本方式

线程概述

利用多线程技术可以使系统同时运行多个程序块,缩短出程序响应的时间,提高计算机资源的利用率,达到多任务处理的目的。

进程和线程

  • 进程是程序的一次动态执行过程,每个进程都有自己独立的内存空间。一个应用程序可以同时启动多个进程(比如浏览器可以开多个窗口,每个窗口就是一个进程)

  • 多进程操作系统能够运行多个进程,每个进程都能够循环利用所需要的CPU时间片,使的所有进程看上去像在同时运行一样。

  • 线程是进程的一个执行流程,一个进程可以由多个线程组成,也就是一个进程可以同时运行多个不同的线程,每个线程完成不同的任务。

  • 线程的并发运行:就是一个进程内若干个线程同时运行。(比如:word的拼写检查功能和首字母自动大写功能是word进程中的线程)

  • 线程进程的关系是一个局部整体的关系,每个进程都由操作系统分配独立的内存地址空间,而同一进程的所有线程都在同一地址空间工作。
    在这里插入图片描述

线程的生命周期

一个线程的完整生命周期要经历5中状态:新建、就绪、运行、阻塞、死亡
在这里插入图片描述
在这里插入图片描述

  • 新建状态:使用new和某种线程的构造方法来创建线程对象,该线程就会进入新建状态,系统为该线程对象分配内存空间。处于新建状态的线程可以通过调用**start()**方法进入就绪状态。
  • 就绪状态:此时线程已经具备了运行的条件,进入了线程队列,等待系统分配CPU资源,一旦获得CPU资源,该线程就会进入运行状态。
  • 运行状态:进入运行在状态,线程会执行自己的**run()**方法中的代码。
  • 阻塞状态:一个正在执行的线程,如果执行了suspend、join或sleep方法,或等待io设备的使用权,那么该线程将会让出自己的CUP控制权并暂时中止自己的执行,进入阻塞状态。阻塞的线程,不能够进入就绪队列,只有当阻塞原因被消除的时候,线程才能进入就绪状态,重新进入线程队列中排队等待CPU资源,然后继续执行。
  • 死亡状态:一个线程完成了全部工作或者被提前强制性的中止,该线程就处于死亡状态。

线程常用方法归纳

方法名描述
Thread(Runnable target)利用Runnable接口子类对象实例化Thread对象
Thread(Runnable target,String name)利用Runnable接口子类实例化Tread对象,并指定线程名
Thread(String name)实例化Thread对象,指定线程名
Thread currentThread()返回当前正在执行的线程
String getName()返回线程名
int getPriority()返回线程优先级
boolean isInterrupter()判断线程是否中断,线程中断返回true,否则返回false
boolean isAlive()判断线程是否活动,是返回true,否则返回false
final void join()强制线程运行(有些任务需要紧急运行)
void run()执行线程,线程执行的主要任务都写里面
void sleep()使正在执行的线程暂时休眠(单位 / 毫秒),其他线程继续执行
interrupt()强制终端线程运行,该线程后面的方法不继续执行
void yield()将目前正在执行等的线程暂停,运行其他线程执行(让给其他线程执行,然后再恢复该线程),不使线程阻塞,即线程任然处于可执行状态,随时可能再次分得CPU时间。
setName()设置线程名
setPriority(int new)设置线程优先级,MIN_PRIORITY(常量值1)最低优先级,NORM_PRIORITY(值5)中等优先级(线程的默认优先级),MAX_PRIORITY(值10) 最高优先级
void start()启动线程,进入就绪队列,等待cpu资源就可以进入运行状态
finalv void setDaemon(boolean on)将一个线程设置成后台运行

多线程的实现方法

案例

1. 继承Thread类,重写run方法来实现多线程
public class MyThread extends Thread{

    private String name;//线程名

    public MyThread() {
    }
    public MyThread(String name) {
        this.name = name;
    }
    
    //完成线程功能的主体代码都在run()方法中
    @Override
    public void run() {
        for (int i = 0; i < 3; i++){
            System.out.println(name + "执行功能" + i);
        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        //定义线程
        MyThread thread1 = new MyThread("线程A");
        MyThread thread2 = new MyThread("线程B");
        MyThread thread3 = new MyThread("线程C");
        MyThread thread4 = new MyThread("线程D");
        MyThread thread5 = new MyThread("线程E");
        MyThread thread6 = new MyThread("线程F");

        //调用start()方法启动线程,让其进入就绪状态,等待系统分配CPU资源进入运行状态调用run()方法
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        thread5.start();
        thread6.start();
    }
}

运行结果:(基于4核计算机)
运行三个线程(顺序执行)
在这里插入图片描述
运行6个线程(交互执行)
在这里插入图片描述

2.继承Runnable接口实现多线程

  重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target

class MyRunnable implements Runnable {

    @Override
    public void run() {
        for(int i = 0; i < 3; i++){
            System.out.println(Thread.currentThread().getName()+"运行功能"+i);
        }
    }
}

public class RunnableDemo {
    public static void main(String[] args) {
        //定义线程
        MyRunnable mt1 = new MyRunnable();
        MyRunnable mt2 = new MyRunnable();
        MyRunnable mt3 = new MyRunnable();
        MyRunnable mt4 = new MyRunnable();
        MyRunnable mt5 = new MyRunnable();
        MyRunnable mt6 = new MyRunnable();

        //利用Runnable接口子类对象来实例化Thread对象
        Thread thrad1 = new Thread(mt1,"线程1");
        Thread thrad2 = new Thread(mt2,"线程2");
        Thread thrad3 = new Thread(mt3,"线程3");
        Thread thrad4 = new Thread(mt4,"线程4");
        Thread thrad5 = new Thread(mt5,"线程5");
        Thread thrad6 = new Thread(mt6,"线程6");

        //启动线程
        thrad1.start();
        thrad2.start();
        thrad3.start();
        thrad4.start();
        thrad5.start();
        thrad6.start();
    }
}

运行结果:
在这里插入图片描述

继承Thread类和实现Runnable接口完成多线程的区别
  • 实现Runnable接口可以做到资源共享,而继承Thread类不行(比如购票问题)
  • 实现Runnable接口相比继承Thread类来说,具有两大优势:避免单继承带来的局限和可以共享资源等优势
  • 相比Thread类的继承,一般采用实现Runnable接口来实现多线程
3. 通过Callable 和 FutureTask创建线程

3.1 创建Callable接口的实现类 ,实现它的Call方法
3.2 使用FutureTask类来包装Callable对象,这个FutureTask对象需要封装Callable对象的Call方法的返回值
3.3 使用FutureTask对象作为Thread对象的target创建并调用start方法启动线程


//1. 创建Callable接口的实现类 ,实现它的Call方法
class MyCallable<T> implements Callable<T>{

    //重写Callable的call方法
    @Override
    public T call() throws Exception {
        System.out.println(Thread.currentThread().getName() + "   ---->通过实现Callable接口来实现线程");
        return null;
    }
}


public class Callable_FutureTask {

    public static void main(String[] args) {

        //2. 实例化Callable对象
        Callable<Object> callable = new MyCallable<Object>();
        //3. 使用FutureTask类来包装Callable对象
        FutureTask<Object> futureTask = new FutureTask<Object>(callable);
        //使用FutureTask对象作为Thread对象的target创建并调用start方法启动线程
        Thread thread1 = new Thread((futureTask),"线程A");

        System.out.println("当前运行线程名:" + Thread.currentThread().getName());
        //启动线程
        thread1.start();
    }

}

运行结果:

在这里插入图片描述

4. 通过线程池实现多线程
class MyRunnable implements Runnable
{
    @Override
    public void run()
    {
        System.out.println("通过线程池的方式创建的线程,线程名 :" + Thread.currentThread().getName());

    }
}

public class ThreadPool {

    //设置线程池的数量
    private static int threadPoolNum = 8;


    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for(int i = 0; i < threadPoolNum; i ++)
        {
            //创建线程对象
            MyRunnable thread = new MyRunnable();

            //Thread.sleep(1000);//使线程休眠1秒
            executorService.execute(thread);
        }
    }
}

运行结果:
在这里插入图片描述

关于线程注意事项

  1. java中,所有线程都是同时启动的,哪个线程占有CPU等运行资源,哪个线程就可以运行。
  2. Java程序每次运行都需要启动两个线程(main线程和垃圾收集器线程)
  3. Java线程运行过程中,其他线程并不会随着主线程的结束而结束。
评论 31
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值