javaSE基础进阶知识笔记5-多线程

本文详细介绍了Java中多线程的创建,包括继承Thread类、实现Runnable接口以及使用Callable接口。还探讨了线程的常用方法,如线程安全问题和解决策略,包括同步代码块、同步方法和Lock锁。此外,文章还讨论了线程通信示例以及线程池的使用,如ThreadPoolExecutor和Executors工具类。最后提到了定时器Timer在并发编程中的应用。

多线程

线程概述

在这里插入图片描述
在这里插入图片描述

线程创建方式

方式一:继承Thread类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package org.example.d1_create;

/**
        目标:多线程的创建方式一,继承Thread类实现
 */
public class Demo1 {
    public static void main(String[] args) {
        //3.new一个新线程对象
        Thread t=new MyThread();
        //4.调用start方法启动线程(执行的还是run方法)
        t.start();

        for (int i = 0; i < 5; i++) {
            System.out.println("主线程启动"+i);
        }
    }
}

/**
        1.定义一个线程类继承Thread类
 */
class MyThread extends Thread{
    /**
            2.重写run方法,里面定义线程以后干啥
     */
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("子线程启动"+i);
        }
    }
}

方式二:实现Runnable接口

在这里插入图片描述
在这里插入图片描述

package org.example.d1_create;

/**
        目标:学会线程的创建方式二,理解它的优缺点
 */
public class ThreadDemo2 {
    public static void main(String[] args) {
        //3.创建一个任务对象
        Runnable target=new MyRunnable();
        //4.把任务对象交给Thread类处理
        Thread t=new Thread(target);
        //5.启动线程
        t.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("主线程执行输出;"+i);
        }
    }
}

/**
        1.定义线程任务类,实现Runnable接口
 */
class MyRunnable implements Runnable{
    //2.重写run方法,定义线程的执行任务

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("子线程执行输出;"+i);
        }
    }
}

在这里插入图片描述

package org.example.d1_create;

/**
 目标:学会线程的创建方式二,使用匿名内部类方式
 */
public class Demo2 {
    public static void main(String[] args) {
        //3.创建一个任务对象
        Runnable target=new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("子线程1执行输出;"+i);
                }
            }
        };
        //4.把任务对象交给Thread类处理
        Thread t=new Thread(target);
        //5.启动线程
        t.start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("子线程2执行输出;"+i);
                }
            }
        }).start();

        new Thread(() ->{
                for (int i = 0; i < 10; i++) {
                    System.out.println("子线程3执行输出;"+i);
                }
            }
        ).start();


        for (int i = 0; i < 10; i++) {
            System.out.println("主线程执行输出;"+i);
        }
    }
}

方式三:实现Callable接口

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

package org.example.d1_create;

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

/**
        目标:学会线程的创建方式三:实现Callable接口,结合FutureTask完成
 */
public class Demo3 {
    public static void main(String[] args) {
        //3.创建Callable任务对象
        Callable<String> call=new MyCallable(100);
        //4.把Callable任务对象交给FutureTask对象
        //FutureTask对象的作用1:是Runnable的对象(实现了Runnable接口)可以交给Thread了
        //FutureTask对象的作用2:可以在线程完毕之后通过调用get方法得到线程执行的结果
        FutureTask<String> f1=new FutureTask<>(call);
        //5.交给线程处理
        Thread t=new Thread(f1);
        //6.启动线程
        t.start();

        Callable<String> call2=new MyCallable(200);
        FutureTask<String> f2=new FutureTask<>(call);
        //5.交给线程处理
        Thread t2=new Thread(f2);
        //6.启动线程
        t2.start();


        try {
            //如果f1任务没有执行完毕,这里的代码会等待,直到线程1跑完才提取结果
            String rs1=f1.get();
            System.out.println("第一个线程结果:"+rs1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            String rs2=f2.get();
            System.out.println("第一个线程结果:"+rs2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

/**
        1.定义一个任务类,实现Callable接口  应该申明线程任务执行完毕后的结果的数据类型
 */
class MyCallable implements Callable<String>{
    private int n;

    public MyCallable(int n) {
        this.n = n;
    }

    /**
        2.重写call方法
     */
    @Override
    public String call() throws Exception {
        int sum=0;
        for (int i = 0; i <= n; i++) {
            sum+=n;
        }
        return ("子线程执行的结果是:"+sum);
    }
}

在这里插入图片描述

线程常用方法

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package org.example.d2_api;

/**
        目标:线程的API
 */
public class Demo1 {
    public static void main(String[] args) {
        Thread t1=new Thread(()-> {
                for (int i = 0; i < 10; i++) {
                    System.out.println("子线程"+Thread.currentThread().getName()+i); }});
        t1.setName("1号");
        t1.start();
        System.out.println(t1.getName());

        Thread t2=new Thread(()-> {
            for (int i = 0; i < 10; i++) {
                System.out.println("子线程"+Thread.currentThread().getName()+i); }});
        t2.setName("2号");
        t2.start();
        System.out.println(t2.getName());

        //哪个线程执行它,它就得到哪个线程对象(当前线程)
        Thread m=Thread.currentThread();
        m.setName("最牛的线程");
        System.out.println(m.getName());
        for (int i = 0; i < 5; i++) {
            System.out.println(m.getName()+"输出:"+i);
        }
    }
}

在这里插入图片描述

package org.example.d2_api;

public class Demo2 {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            System.out.println("输出"+ i);
            if (i==3){
                //让线程进入休眠状态
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}

在这里插入图片描述
在这里插入图片描述

线程安全

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package org.example.d3_thread_safe;


/**
        目标:模拟取钱案例
 */
public class ThreadDemo {
    public static void main(String[] args) {
        //1.定义线程类,创建一个共享账户对象
        Account acc=new Account("ICBC-111",100000.00);
        //2.创建2个线程对象,代表小明和小红同时进来了

        new DrawThread(acc,"小明").start();
        new DrawThread(acc,"小红").start();

    }
}

package org.example.d3_thread_safe;

public class DrawThread extends Thread{
    private Account account;

    public DrawThread(Account acc,String name){
        super(name);
        this.account=acc;
    }

    @Override
    public void run() {
        account.drawMoney(100000.00);
    }
}

package org.example.d3_thread_safe;

public class Account {
    private String card;
    private double money;

    public Account() {
    }

    public Account(String card, double money) {
        this.card = card;
        this.money = money;
    }

    public String getCard() {
        return card;
    }

    public void setCard(String card) {
        this.card = card;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public void drawMoney(double money) {
        //1.判断是谁来取钱
        String name=Thread.currentThread().getName();

        if (this.money>=money){
            //2.取钱
            System.out.println(name+"取钱成功,吐出"+money);
            //3.更新余额
            this.money =this.money-money;
            System.out.println(name+"取钱后剩余:"+this.money);
        }else {
            System.out.println(name+"取钱失败,余额不足");
        }
    }
}

线程同步

在这里插入图片描述
在这里插入图片描述

加锁方式一:同步代码块

在这里插入图片描述
在这里插入图片描述

package org.example.d4_thread_synchronized_code;

public class Account {
    private String card;
    private double money;

    public Account() {
    }

    public Account(String card, double money) {
        this.card = card;
        this.money = money;
    }

    public String getCard() {
        return card;
    }

    public void setCard(String card) {
        this.card = card;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public void drawMoney(double money) {
        //1.判断是谁来取钱
        String name=Thread.currentThread().getName();

        //加锁
        synchronized (this) {
            if (this.money >= money){
                //2.取钱
                System.out.println(name+"取钱成功,吐出"+money);
                //3.更新余额
                this.money =this.money-money;
                System.out.println(name+"取钱后剩余:"+this.money);
            }else {
                System.out.println(name+"取钱失败,余额不足");
            }
        }
    }
}

package org.example.d4_thread_synchronized_code;


public class DrawThread extends Thread{
    private Account account;

    public DrawThread(Account acc, String name){
        super(name);
        this.account=acc;
    }

    @Override
    public void run() {
        account.drawMoney(100000.00);
    }
}

package org.example.d4_thread_synchronized_code;


/**
        目标:模拟取钱案例
 */
public class ThreadDemo {
    public static void main(String[] args) {
        //1.定义线程类,创建一个共享账户对象
        Account acc=new Account("ICBC-111",100000.00);
        //2.创建2个线程对象,代表小明和小红同时进来了

        new DrawThread(acc,"小明").start();
        new DrawThread(acc,"小红").start();

    }
}

加锁方式二:同步方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package org.example.d5_thread_synchronized_method;

public class Account {
    private String card;
    private double money;

    public Account() {
    }

    public Account(String card, double money) {
        this.card = card;
        this.money = money;
    }

    public String getCard() {
        return card;
    }

    public void setCard(String card) {
        this.card = card;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public synchronized void drawMoney(double money) {
        //1.判断是谁来取钱
        String name=Thread.currentThread().getName();

        if (this.money>=money){
            //2.取钱
            System.out.println(name+"取钱成功,吐出"+money);
            //3.更新余额
            this.money =this.money-money;
            System.out.println(name+"取钱后剩余:"+this.money);
        }else {
            System.out.println(name+"取钱失败,余额不足");
        }
    }
}

加锁方式三:lock锁

在这里插入图片描述

package org.example.d6_thread_lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Account {
    private String card;
    private double money;
    //final修饰:锁对象唯一
    private final Lock lock=new ReentrantLock();

    public Account() {
    }

    public Account(String card, double money) {
        this.card = card;
        this.money = money;
    }

    public String getCard() {
        return card;
    }

    public void setCard(String card) {
        this.card = card;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public void drawMoney(double money) {
        //1.判断是谁来取钱
        String name=Thread.currentThread().getName();

        lock.lock();
        try {
            if (this.money>=money){
                //2.取钱
                System.out.println(name+"取钱成功,吐出"+money);
                //3.更新余额
                this.money =this.money-money;
                System.out.println(name+"取钱后剩余:"+this.money);
            }else {
                System.out.println(name+"取钱失败,余额不足");
            }
        } finally {
            lock.unlock();
        }
    }
}

线程通信

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

package org.example.d7_thread_conmminute;

public class Account {
    private String card;
    private double money;

    public Account() {
    }

    public Account(String card, double money) {
        this.card = card;
        this.money = money;
    }

    public String getCard() {
        return card;
    }

    public void setCard(String card) {
        this.card = card;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    /**
        亲爹,干爹,岳父存钱
     * @param money
     */
    public synchronized void deposit(double money){
        try {
            String name=Thread.currentThread().getName();
            if (this.money==0){
                this.money +=money;
                System.out.println(name+ "存钱"+money+"成功,余额为:"+this.money);
                //有钱了,唤醒别人,等待自己
                this.notify();
                this.wait();
            }else {
                //有钱不存
                this.notify();
                this.wait();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 取钱
     * @param money
     */
    public synchronized void drawMoney(double money) {
        try {
            //1.判断是谁来取钱
            String name=Thread.currentThread().getName();

            if (this.money>=money){
                //2.取钱
                System.out.println(name+"取钱成功,吐出"+money);
                //3.更新余额
                this.money =this.money-money;
                System.out.println(name+"取钱后剩余:"+this.money);
                //没钱了
                this.notify();
                this.wait();
            }else {
                System.out.println(name+"取钱失败,余额不足");
                //钱不够,不能取
                //唤醒别人,等待自己
                this.notify();
                this.wait();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

package org.example.d7_thread_conmminute;

public class DrawThread extends Thread{
    private Account account;

    public DrawThread(Account acc, String name){
        super(name);
        this.account=acc;
    }

    @Override
    public void run() {
        while (true) {
            account.drawMoney(100000.00);
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

package org.example.d7_thread_conmminute;

public class DepositThread extends Thread{
    private Account acc;
    public DepositThread(Account acc,String name){
        super(name);
        this.acc=acc;
    }
    @Override
    public void run() {
        while (true) {
            acc.deposit(100000.00);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

package org.example.d7_thread_conmminute;


/**
        目标:了解线程通信的流程
 */
public class ThreadDemo {
    public static void main(String[] args) {
        //使用三个爸爸存钱(生产者),俩个孩子取钱(消费者),模拟线程通信思想
        //创建账户对象,代表五个人共同操作的对象
        Account acc=new Account("ICCBC",0);
        //创建2个线程对象代表小明和小红
        new DrawThread(acc,"小明").start();
        new DrawThread(acc,"小红").start();
        //创建3个线程对象代表三个爸爸
        new DepositThread(acc,"亲爹").start();
        new DepositThread(acc,"干爹").start();
        new DepositThread(acc,"岳父").start();

    }
}

线程池

线程池概述和创建线程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

线程池处理Runnable、Callable任务

在这里插入图片描述
在这里插入图片描述

package org.example.d8_threadpool;

import java.lang.reflect.Executable;
import java.util.concurrent.*;

/**
        目标:自定义一个线程池对象,并测试其特性
 */
public class ThreadPoolDemo1 {
    public static void main(String[] args) {
        //1.创建线程池对象
        /*
        public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)*/
        ExecutorService pool=new ThreadPoolExecutor(3,5,8,
                TimeUnit.SECONDS,new ArrayBlockingQueue<>(5),
                Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
        //2.给任务线程池处理
        Runnable target=new MyRunnable();
        //核心线程处理
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);
        //放进任务队列
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);
        //若核心线程在忙,任务对列已满,则创建临时线程
        pool.execute(target);
        pool.execute(target);
        //若最大线程数在忙,任务队列已满,则抛出异常
        //pool.execute(target);

        //关闭线程池,开发中一般不会使用
        //pool.shutdownNow();//立即关闭,即使任务没有完成,会丢失数据
        pool.shutdown();//会等待任务执行完毕后在进行关闭
    }
}

在这里插入图片描述

package org.example.d8_threadpool;

import java.util.concurrent.Callable;

/**
        1.定义一个任务类,实现Callable接口  应该申明线程任务执行完毕后的结果的数据类型
 */
class MyCallable implements Callable<String>{
    private int n;

    public MyCallable(int n) {
        this.n = n;
    }

    /**
        2.重写call方法
     */
    @Override
    public String call() throws Exception {
        int sum=0;
        for (int i = 0; i <= n; i++) {
            sum+=n;
        }
        return (Thread.currentThread().getName()+"线程执行1--->"+n+"的和是:"+sum);
    }
}

package org.example.d8_threadpool;

import java.util.concurrent.*;

/**
        目标:自定义一个线程池对象,并测试其特性
 */
public class ThreadPoolDemo2 {
    public static void main(String[] args) throws Exception {
        //1.创建线程池对象
        /*
        public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)*/
        ExecutorService pool=new ThreadPoolExecutor(3,5,8,
                TimeUnit.SECONDS,new ArrayBlockingQueue<>(5),
                Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
        //2.给任务线程池处理
        Future<String> f1 = pool.submit(new MyCallable(100));
        Future<String> f2 = pool.submit(new MyCallable(200));
        Future<String> f3 = pool.submit(new MyCallable(300));
        Future<String> f4 = pool.submit(new MyCallable(400));
        Future<String> f5 = pool.submit(new MyCallable(500));

        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());
        System.out.println(f5.get());
    }
}

Executors的工具类构建线程池对象

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package org.example.d8_threadpool;


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

/**
        目标:使用Executors的工具方法直接接得到一个线程池对象
 */
public class ThreadPoolDemo3 {
    public static void main(String[] args) {
        //1、创建固定线程数据的线程池
        ExecutorService pool = Executors.newFixedThreadPool(3);
        pool.execute(new MyRunnable());
        pool.execute(new MyRunnable());
        pool.execute(new MyRunnable());
        pool.execute(new MyRunnable());
    }
}

补充知识

定时器

在这里插入图片描述

在这里插入图片描述

Timer定时器的特点和存在的问题

  1. Timer是单线程,处理多个任务按照顺序执行,存在延时与设置定时器的时间有出入。
  2. 可能因为其中的某个任务的异常使Timer线程死掉,从而影响后续任务执行。

在这里插入图片描述

package org.example.d9_timer;


import com.sun.jmx.snmp.tasks.Task;

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

/**
 目标:Timer定时器的使用和了解
 */

public class TimerDemo2 {
    public static void main(String[] args) {
        //创建一个ScheduledExecutorService对象,做定时器
        ScheduledExecutorService pool= Executors.newScheduledThreadPool(3);

        //开启定时任务
        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"执行了AAA\t"+ new Date());
                try {
                    Thread.sleep(10000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        },0,2, TimeUnit.SECONDS);


        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"执行了BBB\t"+new Date());
                System.out.println(10/0);
            }
        },0,2, TimeUnit.SECONDS);


        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"执行了CCC\t"+new Date());
            }
        },0,2, TimeUnit.SECONDS);
    }
}

并发并行

在这里插入图片描述

在这里插入图片描述

线程的生命周期

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

参考视频

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值