多线程基础详解

多线程基础

一、初识多线程

普通方法和多线程:

在这里插入图片描述

进程process和线程thread

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

创建线程的方式

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

通过继承Tread类

实战演示:

package com.yan;

/**
 * @author :Yan Guang
 * @date :Created in 2021/1/12 18:57
 * @description:  单核cpu只能实现单线程,因为cpu执行速度很快,
 * 所以这里是视作为多线程,但是实际上还是交替执行的(由CPU调度实现),并不是一起执行的;
 * 但是由于这个时间很短很短,所以看起来可以是作为是同步执行的
 */
public class demo01 extends Thread{
    @Override
    public void run() {
        //run方法线程
        for (int i = 0; i < 20; i++) {
            System.out.println("run线程~~~~~~~~~~~~~~~~");
        }
    }

    public static void main(String[] args) {
        demo01 thread1 = new demo01();
        //这里相当于开辟了一条新的线程,但是默认会执行run方法
        thread1.start();
        //main主线程,两条线程是同时执行,交替执行的
        for (int i = 0; i < 1000; i++) {
            System.out.println("main线程~");
        }
    }
}

搞完收工~

通过实现Runnable接口

在这里插入图片描述

package com.yan;

/**
 * @author :Yan Guang
 * @date :Created in 2021/1/12 19:53
 * @description:
 */
public class demo2 implements Runnable{
    @Override
    public void run() {
        //run方法线程
        for (int i = 0; i < 20; i++) {
            System.out.println("run线程~~~~~~~~~~~~~~~~");
        }
    }

    public static void main(String[] args) {
        //这里跟demo1里面的不一样,在Thread构造方法里面加入了Runnable参数
        new Thread(new demo2()).start();
        //main主线程,两条线程是同时执行,交替执行的
        for (int i = 0; i < 1000; i++) {
            System.out.println("main线程~");
        }
    }
}

这里的Thread类也实现了Runnable接口~继承Thread的时候不一定非要重写run方法,是因为start()方法的调用不得不使用run()方法,没有目标target则无法用start()方法,还有一种方法是实现Callable接口,但是用的不多,所以在这里就不演示了
在这里插入图片描述

数据冲突问题

package com.yan;

/**
 * @author :Yan Guang
 * @date :Created in 2021/1/14 20:08
 * @description:
 */
public class demo3 implements Runnable{
    private int tickName = 10;
    @Override
    public void run() {
        while (true) {
            if (tickName <= 0) {
                break;
            }
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "-->拿到了第" + tickName-- + "票");
        }
    }

    public static void main(String[] args) {
        demo3 ticket = new demo3();
        new Thread(ticket,"小黄").start();
        new Thread(ticket,"小名").start();
        new Thread(ticket,"小红").start();
    }
}

在这里插入图片描述
多个线程操作同一个资源的情况下,线程不安全,并发问题(在同一个CPU下,多个线程同时发起的任务请求,出现的问题就叫并发问题),数据紊乱。

二、深入了解Thread类

静态代理

在这里插入图片描述
这里首先you和weddingCompany是接口wedding的实现类,然后weddingCompany通过构造方法,需要传入一个you对象,从而代理可以帮you对象做一些事情,这就是静态代理;同理我们可以对比一下创造一个线程的时候,因为Thread是继承Runnable接口的,然后传入的参数类型也是Runnable接口类型,相当于是代理模式,Thread代理了Runnable接口实现了里面的方法,跟这里的weddingCompany代理you实现了里面的方法是一个道理。

三、Lamda表达式

简介

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

函数式接口

在这里插入图片描述

静态内部类

在这里插入图片描述

局部内部类

在这里插入图片描述

匿名内部类

在这里插入图片描述

lamda表达式

在这里插入图片描述
其实也就是把匿名内部类稍有改变,就是把new 实现类名给省略了,然后直接写函数式接口里面唯一的一个方法里面的内容就可以了,参数类型也可以省略

总结

在这里插入图片描述

四、线程的五大状态(生命周期)

在这里插入图片描述

线程的方法

在这里插入图片描述

线程停止的方法

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

线程礼让

在这里插入图片描述
记住:礼让不一定成功,看CPU心情

线程休眠

在这里插入图片描述
模拟网络延时:放大问题的发生性
在这里插入图片描述

Join

在这里插入图片描述
因为这里是并发执行的,所以main会先跑,然后我们这里用join方法让线程插队进来了

线程状态观测

在这里插入图片描述
死亡之后的线程不能再次启动了

线程的优先级

在这里插入图片描述

守护线程

在这里插入图片描述
守护线程可以理解为守护我们程序正常执行的线程,不用去管它们,我们可以通过setDaemon方法把用户线程升级为守护线程,虚拟机只用保证把用户线程执行完就可以了,守护线程不需要执行完

五、线程同步

介绍

发生在多个线程操作一个资源
在这里插入图片描述
并发就是多线程去抢占一个资源(包括CPU)
在这里插入图片描述
同步就是排队机制,线程一个个进入队列,资源每次都是一对一的跟线程进行操作,同步就是由队列+锁构成的
在这里插入图片描述

线程不安全例子

package com.yan.syn;

/**
 * @author :Yan Guang
 * @date :Created in 2021/1/17 10:42
 * @description:
 */
public class UnSafeBuyTicket {
    public static void main(String[] args){
        BuyTicket station = new BuyTicket();
        new Thread(station,"小红").start();
        new Thread(station,"小章").start();
        new Thread(station,"小蓝").start();
    }
}

class BuyTicket implements Runnable{

    private int ticketNums=10;
    boolean flag=true;

    @Override
    public void run() {
        while (flag){
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void buy() throws InterruptedException {
        if (ticketNums<=0){
            flag=false;
            return;
        }
        Thread.sleep(100);
        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
    }
}
package com.yan.syn;

/**
 * @author :Yan Guang
 * @date :Created in 2021/1/17 11:04
 * @description:
 */
public class UnSafeBank {
    public static void main(String[] args) {
        Account account = new Account(100, "结婚基金");
        GetMoney you = new GetMoney(account,50,"你");
        GetMoney youWife = new GetMoney(account,100,"你妻子");
        you.start();
        youWife.start();
    }
}
class Account{
    int money;
    String name;

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}

class GetMoney extends Thread{
    private Account account;
    private int drawingMoney;//取了多少钱
    private int nowMoney;

    public GetMoney(Account account, int drawingMoney,String name) {
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    @Override
    public void run() {
        if (account.money-drawingMoney<0){
            System.out.println(Thread.currentThread().getName()+"卡里的钱不够了");
            return;
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        account.money = account.money-drawingMoney;
        nowMoney=nowMoney+drawingMoney;
        System.out.println(account.name+"余额为"+account.money);
        System.out.println(Thread.currentThread().getName()+"手里还剩余的钱为"+nowMoney);
    }
}
public class UnSafeArrayList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 50000; i++) {
            new Thread(()-> {
                list.add(Thread.currentThread().getName());
            }).start();
        }
        Thread.sleep(1000);
        System.out.println(list.size());
    }
}

可能在同一个index上后面进来的数据把前面的给覆盖掉了,所以线程是不安全的

解决办法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
锁的是方法的调用者(对象),休眠状态不会释放锁(继续保持锁住状态),这里是三个线程操作一个对象,调用方法锁的是对象车站,将这一个车站的数据都锁住了
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
这里两个线程进行操作,锁不住,多个线程只会锁住当前实例对象,这里是两个线程各自操作各自的对象,锁方法锁的是调用者,所以锁的是银行,而不是账户,所以我们需要将账户进行加锁,使用同步块
在这里插入图片描述
锁的对象就是变化的量,需要增删改的量
在这里插入图片描述
这里也是一个道理,把改变的变量锁住就可以了,这里改变的是list集合对象,锁住就完事儿了
ArrayList是线程不安全的,CopyOnWriteArrayList是线程安全的。

六、死锁

介绍

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

解决办法

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

小结

加上synchronized同步块的资源每次进来的对象都需要带着锁,当有两把锁的时候,锁住了当前的资源别人想要得到你的资源的时候,你却锁住了不放,就造成了死锁,这里的解决办法就是把我当前资源锁住之后,锁完就放,然后再去找你要你的东西就解决了,synchronized同步块运行结束之后就会释放锁,这里还没有释放锁就想着就找别人要资源,别人又要你的资源,东西就都锁住了,谁也不愿意释放,就死锁了,放在外面就相当于释放了我的东西了。

介绍

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

对比

在这里插入图片描述

七、线程协作(生产消费者模式)

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

解决方式一

package com.yan.gaoji;

import com.sun.org.apache.bcel.internal.generic.PUSH;

/**
 * @author :Yan Guang
 * @date :Created in 2021/1/17 12:14
 * @description:
 */
public class TestPC {
    public static void main(String[] args) {
        hunCun hunCun = new hunCun();

        new Productor(hunCun).start();
        new Customer(hunCun).start();
    }
}
//生产者只顾生产,一直往缓存区里面加鸡
class Productor extends Thread{
    hunCun chun;

    public Productor (hunCun hunCun){
        this.chun=hunCun;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("生产了"+i+"只鸡");
            try {
                chun.push(new Chicken(i));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//消费者只顾消费,一直往缓存区里面取鸡
class Customer extends Thread{
    hunCun chun;

    public Customer (hunCun hunCun){
        this.chun=hunCun;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                System.out.println("消费了"+chun.pop().no+"只鸡");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Chicken {
    int no;

    public Chicken(int no) {
        this.no = no;
    }
}


class hunCun{
    Chicken[] chickens = new Chicken[10];
    int count =0;

    public synchronized void push(Chicken chicken) throws InterruptedException {
        if (count==chickens.length){
            //通知生产者等待
            this.wait();
        }
        chickens[count]=chicken;
        count++;
        //如果缓存区没有满,就唤醒生产者继续生产
        this.notify();
    }

    public synchronized Chicken pop() throws InterruptedException {
        if (count==0){
            //让消费者等待
            this.wait();
        }
        count--;
        //通知消费者可以消费了
        this.notify();
        return chickens[count];
    }
}

解决方式二

package com.yan.gaoji;

/**
 * @author :Yan Guang
 * @date :Created in 2021/1/17 12:41
 * @description:
 */
public class TestPC2 {
    public static void main(String[] args) {
        Chicken2 chicken2 = new Chicken2();
        new Product(chicken2).start();
        new Eat(chicken2).start();
    }
}
//生产者只顾生产,一直往缓存区里面加鸡
class Product extends Thread{
    Chicken2 chicken2;
    public  Product(Chicken2 chicken2){
        this.chicken2=chicken2;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                chicken2.zuo();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//消费者只顾消费,一直往缓存区里面取鸡
class Eat extends Thread{
    Chicken2 chicken2;
    public  Eat(Chicken2 chicken2){
        this.chicken2=chicken2;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                chicken2.eat("一只小小鸡");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Chicken2 {
    String eat;
    //如果为真,就吃,不能做,为假就做,不能吃
    boolean flag=true;

    public synchronized void eat(String eat) throws InterruptedException {
        //让消费者先不吃,生产者做
        if (!flag){
            this.wait();
        }
        System.out.println("吃了"+eat);
        //让消费者吃
        this.notifyAll();
        this.eat=eat;
        flag=!flag;
    }
    public synchronized void zuo() throws InterruptedException {
        //让生产者先不做,消费者吃
        if (flag){
            this.wait();
        }
        System.out.println("做了"+eat);
        //让生产者做,消费者吃
        this.notifyAll();
        flag=!flag;
    }
}



线程池

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

线程池创建的方法
public class TestMoreTread {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);

        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());

        service.shutdown();
    }
}

class MyThread implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值