多线程相关笔记

本文详细介绍了多线程的概念,包括进程、线程调度、同步与异步、并发与并行。深入讲解了Java中实现多线程的方式,如Thread类、Runnable接口,并对比了两者的优缺点。此外,还探讨了线程的命名、休眠、阻塞、中断、守护线程以及线程安全。最后,介绍了线程池ExecutorService的重要性和四种类型的线程池,以及如何利用lambda表达式进行函数式编程。
摘要由CSDN通过智能技术生成

进程

  • 是指一个内存运行的应用程序,每一个进程都有一个独立的内存空间
  • 一个进程启动后,里面若干的执行路径可划分为若干线程

线程

  • 在进程的基础上进行划分的是它的一个执行路径,共享一个内存空间
  • 线程之间可以自由切换,并发执行
  • 一个进程最少有一个线程

线程调度

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

同步与异步

  • 同步:排队执行,效率低但是安全
  • 异步:同时执行,效率高但不安全

并发与并行

  • 并发:两个或多个事件在同一时间段内发生
  • 并行:两个或多个事件在同一时间刻发生

在Java中实现多线程技术

  • Thread类:提供的用于实现线程的类
public class myThread extends Thread{
    /**
     *run 方法就是线程要执行的任务方法
     */
     public void run(){
         //这里代码就是一条路径
         //这个执行路径的处罚方式,不是调用run方放,而是通过Thread对象的start()来启动任务
         for(int i=0;i<10;i++){
             System.out.ptintln("我爱学习"+i);
         }
     }
}
//重新创建一个类
public class Try{
    public static void main(String[] args){
    //Thread
    myThread m = new myThread();
    m.start();
        for(int i=0;i<10;i++){
             System.out.ptintln("学习爱我"+i);
         }
    }
}
//分配时抢占式分配 两个线程 每次执行结果都可能不一样

  • 实现Runnable接口
  • 优势:
    • 通过创建线程任务再分配的方式来实现,更适合多个线程同时执行相同任务情况
    • 可避免单线程带来的局限
    • 任务与线程时分离的,提高程序健壮性
    • 后续学习的线程池技术,接受该类型任务,不接受Thread类线程
public class myRunnable implements Runnable{
    @Override
    public void run(){
        //线程的任务
        for(int i=0;i<10;i++){
             System.out.ptintln("我爱学习"+i);
         }
    }
}
//这个类写好之后就相当于有了一个给线程执行的任务
//实现该任务还得借助于Thread
public static void main(String[] args){
    //实现Runnaale
    //1.创建一个任务对象
    myRunnable r = new Runnaale();
    //2.创建一个线程,为其分配任务
    myThread m = new myThread(r);
    m.start();
    
    for(int i=0;i<10;i++){
         System.out.ptintln("学习爱我"+i);
    }
}

设置和获取线程名称

System.out.println(Thread.currentThread().getName ());
//Thread.currentThread() 获取当前正在执行的线程对象
//得到的类型是Thread

线程休眠sleep

    for(int i=0;i<10;i++){
         System.out.ptintln(i);
         Thread.sleep(millis:1000);
         //里面能添毫秒/毫秒加纳秒
         //millis:1000 一千毫米==一秒
    }

线程阻塞

  • 所有比较消耗时间的操作

线程的中断

  • 一个线程是一个独立的执行路径,它是否应该结束应有自身决定
  • 通过打入中断标记来进行,线程在特殊情况时会去查看标记并抛出异常
  • 早期有stop这个方法来从外部掐掉线程,弊端是线程后续操作无法执行
public class Try{
    public static void main(String[] args){
        Thread t1 =new Thread( new myRunnable()); 
        t1.start();
        for(int i=0;i<10;i++){
            System.out.ptintln(Thread.currentThread().getName ()+":"+i);
             try{
                 Thread.sleep(millis:1000);
             }catch(InterruptedException e){
                 e.printStackTrace();
             }
        }
        //给线程t1设置中断标记
        t1.interrupt();
    }
}

public class myRunnable implements Runnable{
    @Override
    public void run(){
        for(int i=0;i<10;i++){
             System.out.ptintln(Thread.currentThread().getName ()+":"+i);
             //因为父类没有抛出异常 所以子类无法使用超出父类的操作
             try{
                 Thread.sleep(millis:1000);
             }catch(InterruptedException e){
                 //e.printStackTrace();
                 //1.发现中断标记了 选择让其自杀
                 System.out.ptintln("发现了中断标记让其自杀");
                 return;
                 //2.也可以发现了中断但是不做处理
                 System.out.ptintln("发现了中断标记不做处理");
             }
         }
    }
}

守护线程

  • 线程分为守护线程和用户线程
  • 用户线程:当一个进程不包含任何的存活用户线程时,进行结束
  • 守护线程:当最后一个用户线程结束时,所有守护线程都自动死亡
    Thread t1 =new Thread( new myRunnable()); 
    //设置成守护线程
    t1.setDaemon(true);
    t1.start();

保证线程安全

隐式锁

  • 同步代码块
    • 格式:synchronized(锁对象){} 锁对象必须是同一把锁 {}里是被执行的操作
  • 同步方法
static class Ticket implements Runnable{
    //票数
    private int cpunt = 10;
    public void run(){
        while(true){
            booleanb flag = sale();
            if(!flag){
            break;
            }
        }
     }
}
public synchronized boolean sale(){
    if(count>0){
    //卖票
    System.out.ptintln("准备卖票");
    try{
        Thread.sleep(millis:1000);
    }catch(InterruptedException e){
        e.printStackTrace();
    }
    count--;
    System.out.ptintln(Thread.currentThread().getName ()+"出票成功,余票:"+count);
    return true;
    }else{
     //break;
     return false
    }
}

显式锁Lock

static class Ticket implements Runnable{
    //票数
     private int cpunt = 10;
     //显式锁
     Look lock = new Rentrant();
     public void run(){
        while(true){
            lock.lock();
            if(count>0){
            //卖票
            System.out.ptintln("准备卖票");
            try{
                Thread.sleep(millis:1000);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            count--;
            System.out.ptintln(Thread.currentThread().getName ()+"出票成功,余票:"+count);
            }else{
            //break;
            break;
            }
            lock.unLock();
        }
    }

线程的六种状态

  • new 尚未启动的线程处于此状态
  • runnable 在Java虚拟机中执行的线程
  • blocked 被阻塞等待监视器锁定的线程
  • waiting 无限期等待另一个线程执行特定操作的线程
  • timewaiting 正在等待另一个线程执行最多指定等待时间的操作的线程
  • terminated 已退出的线程

Callbale

runnable与callbale

接口定义
//callbale接口

public interface Callable<v>{
    v call() throws Exception;
}

//runnable接口

public interfac runnable{
    
    public abstract void run();
}

callbale使用步骤

1. 编写类实现callbale接口 实现call()方法
    class xxx implements callbale<>{
        public<T> call() throws Exception{
            return T;
        }
    }
    
2. 创建FutureTask对象 并传入第一步编写的callbale类对象
    FutureTask<Integer> future = new FutureTask<>(callable);

3. 通过Thread 启动线程
    new Thread(future).start();
//使用例子
public static void main(String[] args){
    Callbale<Integer> c = new myCallbale();
    FutureTask<Integer> task = new FutureTask<>(c);
    task.isDone();//判断线程是否执行完毕
    task.cancel();//取消线程()里是布尔类型的
    new Thread(task).start();
    Integer j = task.get();
    System.out.ptintln("返回值为:"+J);
    forint i=0;i<10;i++){
        try{
            Thread.sleep(millis:100);
        }catch(InterruptedException e){      
            e.printStackTrace();
        }
        System.out.ptintln(i);
        }
}
static class myCallable implements Callable<Integer>{
    public Integer call() throws Exception{
        //Thread.sleep(3000);
        forint i=0;i<10;i++){
            try{
                Thread.sleep(millis:100);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.ptintln(i);
        }
    }
}

runnable与callbale的相同点

  • 都是接口
  • 都可以编写多线程程序
  • 都采用Thread.start()启动线程

线程池 Executors

  • 如果并发执行的线程较多,每个线程执行任务的时间也很短,那么频繁创建线程、销毁线程会大大降低系统的效率
  • 线程池是一个容纳多个线程的容器,池中线程可以反复使用
    好处
  • 降低资源消耗、提高反应速度、提高线程可管理性

java中四种线程池 ExecutorService

  • 缓存线程池
    • 判断池中是否有空闲线程有就使用,没有的话创建线程放入缓存池中再使用
public class Demo1 {
    /**
     *缓存线程池
     *(长度无限制)
     * 任务加入后的执行流程:
     * 1.判断线程池是否存在空闲线程
     * 2.存在则使用
     * 3.不存在,则创建线程并放入线程池,然后使用
     */
    public static void main(String[] args) {
        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()+"我爱学习");
            }
        });
        try{
            Thread.sleep(1000);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
    }
}
  • 定长线程池
    • 判断是否有空闲,没有且线程池未满的情况下创建再使用,若池满则等待空闲
public class Demo2 {
    /**
     * 定长线程池.
     * (长度是指定的数值)
     * 任务加入后的执行流程:
     * 1.判断线程池是否存在空闲线程2.存在则使用
     * 3.不存在空闲线程,且线程池未满的情况下,则创建线程并放入线程池,然后使用
     * 4.不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
     */
    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() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"我爱学习");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {

                System.out.println(Thread.currentThread().getName()+"我爱学习");
            }
        });
    }
}
  • 单线程线程池
    • 空闲用不空闲等待
public class Demo3 {
    /**
     * 单线程线程池.
     * 执行流程:
     * 1.判断线程池的那个线程是否空闲
     * 2.空闲则使用
     * 3.不空闲,则等待池中的单个线程空闲后使用
     */
    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()+"我爱学习");
            }
        });
    }
}
  • 周期性任务定长线程池
    • 可定时间隔时长周期重复执行
public class Demo4 {
    /**
     * 周期任务定长线程池.
     * 执行流程:
     * 1.判断线程池是否存在空闲线程
     * 2.存在则使用
     * 3.不存在空闲线程,且线程池未满的情况下,则创建线程并放入线程池,然后使用
     * 4.不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
     *
     * 周期性任务执行时:
     * 定时执行,当某个时机触发时,自动执行某任务﹒
     */
    public static void main(String[] args) {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
        /**
         * 1.定时执行一次
         * 参数1.定时执行的任务
         * 参数2.时长数字
         * 参数3.时长数字的时间单位,TimeUnit的常量指定

        service.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"我爱学习");
            }
        },5, TimeUnit.SECONDS);//五秒钟后执行*/
        /**
         * 周期性执行任务
         * 参数1.任务
         * 参数2.延迟时长数字〔第一次执行在什么时间以后)
         * 参数3.周期时长数字〔每隔多久执行一次)
         * 参数4.时长数字的单位
         */
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"学习爱我");
            }
        },5,1,TimeUnit.SECONDS);//五秒钟后执行第一次,再每间隔一秒执行一次
    }
}

lambda表达式

函数式编程思想
面向对象:创建对象调用方法解决问题.

public class Lambda {
    public static void main(String[] args) {
        //冗余的Runnable代码
        /*
        Thread t = new Thread(new Runnable( ){
        @Override
        public void run() {
            System.out.println("我爱学习");
            }
        });
        t.start();*/

        Thread t = new Thread((/*参数*/)->{
            System.out.println("我爱学习");
            //这个大括号里可以写多个内容用;隔开
        });
        t.start();
    }
}
public class Lambda2 {
    public static void main(String[] args) {
        //修改前
        print(new MyMath() {
            @Override
            public int sum(int x, int y) {
                return x+y;
            }
        },100,200);
        //修改后 保留方法参数部分和方法体
        print((int x, int y) ->{
                return x+y;
        },100,200);
    }

    public static void print(MyMath m,int x, int y){
        int num = m.sum(x, y);
        System.out.println(num);
    }
    static interface MyMath{
        int sum(int x,int y);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值