多线程笔记二(狂神说):

本文详细介绍了Java中的多线程概念,包括线程的状态、停止、礼让、强制执行、线程同步、优先级、守护线程、死锁以及Lock锁。同时,文章还探讨了静态代理模式,展示了如何通过代理对象增强真实对象的功能。通过实例代码,展示了线程的创建和管理,以及在实际场景中的应用。
摘要由CSDN通过智能技术生成

 目录

静态模式总结:真实对象和代理对象都要实现同一个接口

代理对象要代理真实角色代理对象可以做很多真实对象做不了的事情

真实对象只专注做自己的事情

线程的五大状态:

线程停止:

线程礼让:

线程强制执行:

观测线程状态:

线程的优先级:

守护线程:

线程同步:

线程同步

JUC

死锁

Lock 锁

线程协作——生产消费者模式

信号灯法

线程池


静态模式总结:真实对象和代理对象都要实现同一个接口

代理对象要代理真实角色代理对象可以做很多真实对象做不了的事情

真实对象只专注做自己的事情

案例:

public class StaticProxy {
    
    public static void main(String[] args) {
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                System.out.println("我爱你");
            }
        };
        new Thread(runnable).start();
​
        WeddingCompany weddingCompany=new WeddingCompany(new You());
        weddingCompany.HappyMarry();
​
​
    }
}
​
interface Marry{
​
    void HappyMarry();
}
​
class You implements Marry{
​
    @Override
    public void HappyMarry() {
        System.out.println("我要结婚了,happy");
    }
}
​
//代理对象帮助你结婚
class WeddingCompany implements Marry{
     //代理真实目标对象
    private Marry target;
    public WeddingCompany(Marry target){
        this.target=target;
    }
    @Override
    public void HappyMarry() {
        brfore();
        //真实对象
        this.target.HappyMarry();
        after();
    }
    private void brfore(){
        System.out.println("结婚之前布置现场");
    }
    private void after(){
        System.out.println("结婚之后收尾款");
    }
}

线程的五大状态:

img

在这里插入图片描述

在这里插入图片描述

线程停止:

package com.langsin.thread;
/*
测试stop
1.建议现成正常停止--->利用次数,不建议死循环
2.建议使用标志位-->设置一个标志位
3.不要使用stop或者destroy等过时或者不建议使用的方法
 */
public class TestStop implements Runnable {
    private boolean flag=true;
    @Override
    public void run() {
        int i=0;
        while (flag){
            System.out.println("run.....Thread"+(i++));
        }
    }
    public void stop(){
        this.flag=false;
    }
​
    public static void main(String[] args) {
        TestStop testStop=new TestStop();
        new Thread(testStop).start();
        for (int i = 0; i <1000 ; i++) {
            System.out.println("main"+i);
            if (i==900){
                testStop.stop();
                System.out.println("run线程停止了!");
            }
        }
    }
}

线程礼让:

礼让线程,让当前正在执行的线程暂停,但不阻塞

将线程从运行状态转为就绪状态

让CPU重新调度,礼让不一定成功

package MultiThread;
​
public class TestYield {
    public static void main(String[] args) {
        MyYield myYield=new MyYield();
        new Thread(myYield,"a").start();
        new Thread(myYield,"b").start();
    }
}
class MyYield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程开始执行");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"线程结束执行");
    }
}
​

礼让成功

在这里插入图片描述

礼让失败

在这里插入图片描述

其实这里注释掉yield,还是会出现a先执行或者b先执行的情况,因为是多线程的原因

线程强制执行:

join 合并线程,待此线程结束之后,在执行其他线程,其他线程阻塞,可以想象成插队

package MultiThread;
​
public class TestJoin implements Runnable {
​
    public static void main(String[] args) throws InterruptedException {
        TestJoin testJoin=new  TestJoin();
        Thread thread=  new Thread( testJoin);
        thread.start();
​
        for (int i = 0; i < 50; i++) {
          if(i==25)
          {
              thread.join();
          }
            System.out.println("主线程"+i);
        }
    }
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println("join线程"+i);
        }
    }
}
​

注意join是通过new Thread 对象来调用的,而sleep和yield是通过Thread直接调用

观测线程状态:

Thread.State

NEW 尚未启动的线程处于此状态。RUNNABLE RUNNABLE 在Java虚拟机中执行的线程处于此状态 BLOCKED 被阻塞等待监视器锁定的线程处于此状态 – – WA工TING 正在等待另一个线程执行特定动作的线程处于此状态 TIMED_ WA工TING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。 TERMINATED 已退出的线程处于此状态

一个线程可以给定时间点处于一个状态。这些状态是不反映任何操作系统线程状态的虚拟机状态

public class TestState {
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            for (int i = 0; i <5 ; i++) {
                try {
                    Thread.sleep(1000);
​
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("");
        });
        Thread.State state = thread.getState();
        System.out.println(state);//new
        thread.start();//启动线程
        state=thread.getState();//runnable
        System.out.println(state);
        while (state!= Thread.State.TERMINATED){//只要线程不终止就输出线程状态
            Thread.sleep(100);
            state=thread.getState();//更新线程状态
            System.out.println(state);//TIME_WAITING
            
        }
    }
}

死亡之后的线程不能再次启动

线程的优先级:

  • Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级来决定应该调度哪个线程来执行。

  • 线程的优先级用数字表示,范围从1~10.

    • Thread.MIN_PRIORITY = 1;

    • Thread.MAX_PRIORITY = 10;

    • Thread.NORM_PRIORITY = 5;

  • 使用以下方法改变或获取优先级

    • getPriority.setPriority(int xxx)

      public class TestPriority {
          public static void main(String[] args) {
              //主线程默认优先级
              System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
      ​
              MyPriority mp=new MyPriority();
              Thread t1=new Thread(mp);
              Thread t2=new Thread(mp);
              Thread t3=new Thread(mp);
              Thread t4=new Thread(mp);
              Thread t5=new Thread(mp);
              Thread t6=new Thread(mp);
      ​
              //先设置优先级,再启动
               t1.start();
               t2.setPriority(1);
               t2.start();
      ​
               t3.setPriority(4);
               t3.start();
              //max值为10
               t4.setPriority(Thread.MAX_PRIORITY);
               t4.start();
      //         t5.setPriority(-1);
      //         t5.start();
      ​
      //         t6.setPriority(11);
      //         t6.start();
          }
      }
      ​
      class MyPriority implements Runnable{
      ​
          @Override
          public void run() {
              System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
          }
      }

总结:优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用了。这都看CPU的调度。

守护线程:

  • 线程分为用户线程和守护线程

  • 虚拟机必须确保用户线程执行完毕(如 main)

  • 虚拟机不用等待守护线程执行完毕(如,后台记录操作日志,监控内存,垃圾回收)

    public class TestDaemon{
        public static void main(String[] args) {
            God god=new God();
            Me me=new Me();
    ​
            Thread thread=new Thread(god);
            thread.setDaemon(true); //默认false表示是用户线程,正常的线程都是用户线程
    ​
            thread.start(); //启动守护线程
    ​
            new Thread(me).start(); //启动用户线程
        }
    }
    class God implements Runnable{
        @Override
        public void run() {
            while (true){
                System.out.println("上帝保佑你");
            }
        }
    }
    ​
    class Me implements Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 36500; i++) {
                System.out.println("你一生都开心的活着");
            }
            System.out.println("=====goodbye world=====");
        }
    }

线程同步:

在这里插入图片描述

多线程访问同一个对象——>并发

队列和锁:上厕所排队,厕所有锁,保证里面的安全

每个对象都有一把锁

在这里插入图片描述

只有前一个对象开锁之后,下一个对象才能访问

案例:买票

package com.ryh.syn;
​
/**
 * @author renyuhua
 * @date 2021年08月14日 23:53
 */
//不安全的买票
    //线程不安全,有负数
    //每个线程都有自己的工作内存
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
​
        new Thread(buyTicket,"小李").start();
        new Thread(buyTicket,"小众").start();
        new Thread(buyTicket,"渣渣").start();
    }
​
}
​
class BuyTicket implements Runnable{
​
    //票
    private int ticketNums = 10;
    boolean flag = true;//外部停止方式
​
    @Override
    public void run() {
        //买票
        while (flag){
            buy();
        }
    }
​
    private void buy(){
        //判断是否有票
        if (ticketNums<=0){
            flag = false;
            return;
        }
​
        //模拟延时
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
​
        //买票
        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
​
    }
}
​

案例:取钱

//不安全取钱
//两个人去银行取钱,账户一致
public class UnsafeBank {
   static class account{
        int money;
        String name;
​
        public account(int money, String name) {
            this.money = money;
            this.name = name;
        }
    }
    static class Drawing extends Thread{
        //账户
        account account;
        //去了多少钱
        int drawingMoney;
        //现在手里有多少钱
        int nowMoney;
​
        public Drawing(account account, int drawingMoney, String name) {
            super(name);
            this.account = account;
            this.drawingMoney = drawingMoney;
​
        }
​
        @Override
        public  void run() {
            synchronized (account){
                //判断没有钱
                if (account.money-drawingMoney<0){
                    System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
                    return;
                }
                try {
                    Thread.sleep(100);
                } 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 static void main(String[] args) {
​
        account account=new account(1000,"结婚基金");
​
        Drawing you=new Drawing(account,50,"你");
        Drawing gf=new Drawing(account,100,"gf");
​
        you.start();
        gf.start();
​
    }
}

案例:线程不安全集合

package com.ryh.syn;
​
import java.util.ArrayList;
import java.util.List;
​
/**
 * @author renyuhua
 * @date 2021年08月15日 0:24
 */
//线程不安全的集合
public class UnsafeList {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 1000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}
​
​

线程同步

在这里插入图片描述

  • 数据对象访问-get-set访问

  • 加synchronized控制对象的访问

  • 方法里面需要修改的内容才需要锁

在这里插入图片描述

案例:同上方取钱代码

监视的对象一定是增删改查的对象

JUC

package com.ryh.syn;
​
import java.util.concurrent.CopyOnWriteArrayList;

​ ​ //测试JUC安全类型的集合
 public class TestJUC { 
   public static void main(String[] args) { 
       CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();   
     for (int i = 0; i < 1000; i++) {  
          new Thread(() -> {      
          list.add(Thread.currentThread().getName()); 
          }).start();       
}  
      try {            Thread.sleep(100);
       } catch (InterruptedException e) { 
           e.printStackTrace();       } 
  }
 } ​ ​

死锁

在这里插入图片描述

在这里插入图片描述

//死锁:多个线程互相拥抱着对方需要的资源
public class DeadLock {
    public static void main(String[] args) {
        Makeup g1=new Makeup(0,"灰姑娘");
        Makeup g2=new Makeup(1,"白雪公主");
​
        new Thread(g1).start();
        new Thread(g2).start();
    }
}
​
//口红
class Lipstick{
​
}
​
//镜子
class Mirror{
​
}
​
class Makeup extends Thread{
//需要的资源只有一份,用static来保证只有一份
    static Lipstick lipstick=new Lipstick();
    static Mirror mirror=new Mirror();
​
    int choice;//选择
    String girlName;//使用化妆品的人
​
    public Makeup(int choice, String girlName) {
        this.choice = choice;
        this.girlName = girlName;
    }
​
    @Override
    public void run() {
        //化妆
        try {
            makeup();
        } catch (Exception exception) {
            exception.printStackTrace();
        }
​
    }
    //化妆,互相持有对方的锁,就是需要拿到对方的资源
    private void makeup() throws Exception{
        if (choice==0){
            synchronized (lipstick){ //获得口红的锁
                System.out.println(this.girlName+"获得口红的锁");
                Thread.sleep(1000);
                }
            //死锁解除
            synchronized (mirror){ //获得镜子的锁
                System.out.println(this.girlName+"获得镜子的锁");
            }
        } else {
            //死锁
            synchronized (mirror){//获得镜子的锁
                System.out.println(this.girlName+"获得镜子的锁");
                Thread.sleep(2000);
                synchronized (lipstick){//获得口红的锁
                System.out.println(this.girlName+"获得口红的锁");
                }
            
            }
        }
    }
}

Lock 锁

在这里插入图片描述

import java.util.concurrent.locks.ReentrantLock;
​
//测试Lock类
public class TestLock {
    public static void main(String[] args) {
        TestLock2 testLock2=new TestLock2();
        new Thread(testLock2).start();
        new Thread(testLock2).start();
        new Thread(testLock2).start();
    }
}
​
class TestLock2 implements Runnable{
    int ticketNums=10;
    //定义Lock锁
    private final ReentrantLock lock=new ReentrantLock();
    @Override
    public void run() {
        while (true){
​
            try {
                lock.lock();
                if (ticketNums > 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(ticketNums--);
                }else {
                    break;
                }
                } catch(Exception e){
                    e.printStackTrace();
                } finally{ //finally最终会实现
                    lock.unlock();
                }
​
​
        }
    }
}

在这里插入图片描述

线程协作——生产消费者模式

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

//测试:生产者消费者模式-->利用缓冲区解决:管程法
//生产者、消费者、产品、缓冲区
public class TestPc {
    public static void main(String[] args) {
        SynContainer container=new SynContainer();
​
        new Productor(container).start();
        new Consumer(container).start();
    }
​
​
}
​
//生产者
class Productor extends Thread{
SynContainer container;
​
    public Productor(SynContainer container) {
        this.container = container;
    }
    //生产
​
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            container.push(new Chicken(i));
            System.out.println("生产了第"+i+"只鸡");
        }
    }
}
//消费者
class Consumer extends Thread{
    SynContainer container;
​
    public Consumer(SynContainer container) {
        this.container = container;
    }
    //消费
​
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了----第"+container.pop().id+"只鸡");
​
        }
    }
}
​
//产品
class Chicken{
    int id;
​
    public Chicken(int id) {
        this.id = id;
    }
}
​
class SynContainer{
    //需要一个容器大小
    Chicken[] chickens=new Chicken[10];
    //容器计数器
    int count=0;
​
    //生产者放入产品
    public synchronized void push(Chicken chicken){
        //如果容器满了,就需要等待消费
        if (count==chickens.length){
            //通知消费者消费,等待生产
            try {
                this.wait();
            }catch (Exception e){
                e.printStackTrace();
            }
​
        }
        //如果没有满,我们就需要丢入产品
        chickens[count]=chicken;
        count++;
​
        //可以通知消费者消费
        this.notifyAll();
    }
​
    //消费者消费商品
    public synchronized Chicken pop(){
        //判断能否消费
        if (count==0){
            //等待生产者生产,消费者等待
            try {
                this.wait();
            } catch (Exception e){
                e.printStackTrace();
            }
        }
​
        //如果可以消费,就取出产品
        count--;
        Chicken chicken=chickens[count];
​
        //可以通知生产者消费了
        this.notifyAll();
        return chicken;
    }
​
    //消费者消费产品
​
}

信号灯法

public class TestPc2 {
    public static void main(String[] args) {
        TV tv=new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}
//生产者--演员
class Player extends Thread{
    TV tv;
​
    public Player(TV tv) {
        this.tv = tv;
    }
​
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if (i%2==0){
                this.tv.play("快乐大本营");
            } else {
                this.tv.play("天天向上");
            }
        }
    }
}
​
//消费者--观众
class Watcher extends Thread{
    TV tv;
​
    public Watcher(TV tv) {
        this.tv = tv;
    }
​
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            tv.watch();
        }
    }
}
​
//产品--节目
class TV{
    //演员表演,观众等待
    //观众观看,演员表演
    String voice; //表演节目
    boolean flag=true;
​
    //表演
    public synchronized void play(String voice){
        if (!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("演员表演了"+voice);
        //通知观众观看
        this.notifyAll();
        this.voice=voice;
        this.flag=!this.flag;
    }
    //观看
    public synchronized void watch(){
        if (flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观看了:"+voice);
        //通知演员表演
        this.notifyAll();
        this.flag=!this.flag;
    }
​
}

线程池

在这里插入图片描述

在这里插入图片描述

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
​
public class TestPool {
    public static void main(String[] args) {
        //1.创建服务,创建线程池
        //newFixedThreadPool 参数为:线程池大小
        ExecutorService service= Executors.newFixedThreadPool(10);
​
        //执行
        service.execute(new MyThread());
        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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值