多线程简述

2021/5/1 18:25:25

本文主要是介绍多线程简述,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

多线程

  • 一、多线程概述
    • 1.线程与进程
    • 2.线程调度
    • 3.同步与异步
    • 4.并发与并行
  • 二、多线程实现
    • 1.继承Thread类
    • 2.实现Runnable接口
    • 3.实现Callable接口
  • 三、线程池
    • 1.CachedThreadPool
    • 2.FixedThreadPool
    • 3.SingleThreadExecutor
    • 4.ScheduledThreadPool


提示:以下是本篇文章正文内容


一、多线程概述

1.线程与进程

a.线程

  • 是进程中的一条执行路径,共享一个内存空间,线程之间可以自由切换,并发执行。一个进程至少有一个线程
  • 线程实际上是在进程基础上的进一步划分,一个进程启动之后,里面若干执行路径又可以划分为若干线程

b.进程

  • 是指一个内存中运行的应用程序,每一个进程都有一个独立的内存空间

2.线程调度

a.分时调度(轮流)

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

b.抢占式调度(抢)

  • 优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。
  • CPU使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核新而言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是 在同一时刻运行。其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的 使用率更高。

3.同步与异步

a.同步

  • 排队执行、 效率低、安全

b.异步

  • 同时执行、效率高、数据不安全

4.并发与并行

a.并发

  • 指两个或多个事件在同一个时间段内发生

b.并行

  • 指两个或多个事件在同一时刻发生(同时发生)

二、多线程实现

1.继承Thread类

继承Thread、重写run()

public class MyThread extends Thread{
    /**
     * run方法就是线程要执行的任务方法
     */
    @Override
    public void run() {
        //这里的代码,就是一条新的执行路径
        //这个执行路径的触发方式,不是调用run方法,而是通过thread对象的start()来启动任务
        for (int i=0;i<10;i++){
            System.out.println("我是本线程要执行的任务"+i);
        }
    }
}

创建继承Thread的类对象,使用start()启动线程

public class ThreadDemo {

    public static void main(String[] args) {
        //Thread
        MyThread m = new MyThread();
        m.start();
        for (int i=0;i<10;i++){
            System.out.println("我是主线程的任务"+i);
        }
        //每个线程都拥有自己的栈空间,共用一份堆内存
        m.run();


        //常用Thread类构造方法
        //Thread()
        //Thread(Runnable),一参传一个任务
        //Thread(Runnable,name),二参,一个传一个任务,一个传线程名字
        

        //常用的Thread类方法

        //getName
        //getId
        //getPriority  获取线程优先级
        //setPriority  设置线程优先级
        //关于线程优先级 有三个常量 大、小、默认
        //start
        //stop 已过时 方法不安全
        //结束线程 可以 声明一个变量来标记 变量改变则结束线程

        //sleep(1000) 休眠 暂时停止
        //上面是线程休眠1s的方法

        //setDaemon 标记 守护线程 或 用户线程
        //守护线程:守护线程不能控制自己的生命,守护线程依附于用户线程,用户线程结束,守护线程自动死亡
        //用户线程:用户线程即不管是mian线程还是子线程未执行结束 程序都不会结束的线程 都称为用户线程
        //mian线程是主线程,其他为子线程
    }
}

2.实现Runnable接口

实现Runnable接口,重写run()

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            System.out.println(i+"床前上天窗");
        }
    }
}

创建任务对象,创建线程并分配任务,start()启动线程

public class RunnableDemo {

    public static void main(String[] args) {
        //实现Runnable
        //1. 创建任务对象
        MyRunnable r = new MyRunnable();
        //2. 创建一个线程,并为其分配一个任务
        Thread t = new Thread(r);
        //3. 执行这个线程
        t.start();

        for (int i=0;i<10;i++){
            System.out.println("底下没有光"+i);
        }

        //这里是创建匿名Thread对象 的方式创建一个一次性线程
        new Thread(){
            @Override
            public void run() {
                for (int i=0;i<10;i++){
                    System.out.println("匿名类一次性线程"+i);
                }
            }
        }.start();


    }
}

实现Runnable 与 继承Thread相比的优势:

 1. 通过创建任务,然后给线程分配的方式来实现的多线程。更适合多个线程同时执行相同任务的情况
 2. 可以避免单继承所带来的局限性
 3. 任务与线程本身是分离的,提高了程序的健壮性
 4. 后线程池技术,接受Runnable类型的任务,不接受Thread类型的线程

3.实现Callable接口

有返回值的线程Callable

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class MakeThreadByCallable {
    
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        Callable<Integer> c = new MyCallable();
        FutureTask<Integer> task = new FutureTask<>(c);
        new Thread(task).start();

        /**
         * task.isDone();    //判断子线程是否执行完毕
         * task.cancel();    //参数为布尔类型的
         */

        int callableNum = task.get();
        System.out.println("----------------");
        System.out.println(callableNum);
        System.out.println("----------------");

        for (int i=0;i<10;i++){
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName()+i);
        }
    }

    static class MyCallable implements Callable<Integer>{

        @Override
        public Integer call() throws Exception {
            for (int i=0;i<10;i++){
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName()+i);
            }

            return 100;
        }
    }
}

三、线程池

1.CachedThreadPool

CachedThreadPool:缓存线程池(长度无限制)

任务加入后的执行流程:

  1. 判断线程池是否存在空闲线程
  2. 存在则用
  3. 不存在,则创建线程 并放入线程池,然后使用
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CachedThreadPoolDemo {

    public static void main(String[] args) throws InterruptedException {
        //指挥线程池执行新的任务
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":锄禾入党无");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":旱地核下土");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":清名上河图");
            }
        });

        Thread.sleep(2000);

        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":旱地核下土");
            }
        });
    }
}

2.FixedThreadPool

FixedThreadPool:定长线程池(长度是指定任务的数值)

任务加入后的执行流程:

  1. 判断线程池是否存在空闲线程
  2. 存在则使用
  3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池,然后使用
  4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FixedThreadPoolDemo {

    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(2);
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":锄禾入党无");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":旱地核下土");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":清名上河图");
            }
        });
    }
}

3.SingleThreadExecutor

SingleThreadExecutor:单线程线程池

执行流程:

  1. 判断线程池 的那个线程 是否空闲
  2. 空闲则使用
  3. 不空闲,则等待 池中的单个线程空闲后 使用
package ThreadTrain;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SingleThreadExecutorDemo {

    public static void main(String[] args) {
        ExecutorService service = Executors.newSingleThreadExecutor();
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":老子是你儿子");
            }
        });

        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":儿子我是你爹");
            }
        });

        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":老儿我是你爷");
            }
        });
    }
}

4.ScheduledThreadPool

ScheduledThreadPool:定长线程池(周期任务)

执行流程:

  1. 判断线程池是否存在空闲线程
  2. 存在则使用
  3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池,然后使用
  4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程

周期性任务执行时:

  • 定时执行,当某个时机触发时,自动执行某任务。
package ThreadTrain;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolDemo {

    public static void main(String[] args) {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
        /**
         * 方式一  定时执行一次
         * 参数1. 定时执行的任务
         * 参数2. 时长数字
         * 参数3, 时长数字的时间单位,TimeUnit的常量指定

        service.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("你好兄弟");
            }
        },5, TimeUnit.SECONDS);*/

        /**
         * 周期性执行任务
         * 参数1. 任务
         * 参数2. 延迟时长数字(第一次执行在什么时间以后)
         * 参数3. 周期时长数字(每隔多久执行一次)
         * 参数4. 时长单位数字
         */
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("旱地核下土");
            }
        },5,1,TimeUnit.SECONDS);
    }
}




这篇关于多线程简述的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程