黑马程序员_多线程

基础知识

  • 什么是线程
    • 被包含在进程之中, 可以调度的最小单位
    • 应用软件中互相独立,可以同时运行的功能
  • 什么是进程
    • 程序的基本执行实体

总结:

  • 什么是多线程?
    • 有了多线程,可以让程序同时做多件事情
  • 多线程有什么作用?
    • 提供程序的运行效率

  • 并发是什么?
    • 在同一时刻,有多个指令在单个 CPU 上交替执行
  • 并行是什么
    • 在同一时刻,有多个指令在单个 CPU 上同时执行

image.png

在线程中进行并发和并行

多线程的实现方式

第一种继承 Thread 类方式实现:

  1. 定义一个类继承 Thread
  2. 重写 run 方法
  3. 创建对象实例

image.png

image.png

以 Runnable 接口的方式实现

  1. 实现Runnable 接口
  2. 重写方法
  3. 创建实例
  4. 将实例放入 Thread 类对象中

image.png

image.png

Callable接口

有返回值,可以获得多线程的结果

特点:

  1. 创建一个类实现Callable接口
  2. 重写call方法
  3. 创建实例对象
  4. 创建FutureTask对象管理线程结果
  5. 创建Thread类对象 获取结果

image.png

image.png

常见的成员方法

image.png

演示方法:

getName()和setName()

返回线程的名字:
image.png

public class Mythread_01 extends Thread{  
    @Override  
    public void run() {  
        for (int i = 0; i < 100; i++) {  
            System.out.println(getName() + "@" + i);  
        }  
    }  
}

返回的默认名字格式为Thread-序号

  1. 使用setname
  2. 使用Thread(String name)
    1. 但是需要在继承类中使用super方法把带有String的构造方法写出来

线程的优先级

抢占式调度特点:随机

//使用setPriority来设置优先级
t1.setPriority(1);  
t2.setPriority(10);  
t2.start();  
t1.start();

守护线程

当其他非守护线程执行完毕,守护线程会陆续结束

当主线程结束,守护线程是跟着结束

插入线程

image.png

线程.join()

可以讲线程提前用完

线程的生命周期

image.png

线程安全问题

  • 当线程被共享后,其中的数据也会被其他线程修改导致不安全
    • 解决方式:把共享的数据锁起来
      synchronized 锁的特点:
  1. 锁默认打开,有线程进去自动关闭
  2. 代码全部执行完毕,锁自动打开
    image.png
    锁(类的字节码->唯一对象)

同步方法

image.png

image.png

lock锁

image.png
标准写法:

Lock lock = new ReentrantLock();

while(true){  
  //  synchronized (Myrunnable.class){  
    lock.lock();  
    try {  
        if(ticket == 100){  
            break;  
        }else{  
            Thread.sleep(10);  
            ticket++;  
            System.out.println(Thread.currentThread().getName() + " sell " + ticket + " tickets");  
        }  
    } catch (Exception e) {  
        throw new RuntimeException(e);  
    } finally {  
        lock.unlock();  
    }

死锁

死锁是一种错误,需要我们去避免的
特点:

  • A锁等着拿B锁
  • B锁等着拿A锁
  • 互相卡死
    image.png

生产者和消费者

完整过程:
image.png

常见方法

image.png
代码执行的流程:

  1. 循环
  2. 同步代码块
  3. 判断共享数据是否到了末尾(到了末尾)
  4. 判断共享数据是否到了末尾(未到末尾)

分为三块代码:
Desk:控制消费者和生产者的行为

package 生产者消费者;  
  
public class Desk {  
  
  
    //Desk:控制生产者和消费者的行为  
  
    // 是否有面条  
    public static int foodFlag = 0;  
  
    //制造的个数  
    public static int count = 10;  
  
    //锁对象  
    public static Object lock = new Object();  
}

Cook:生产者

package 生产者消费者;  
  
public class Cook extends Thread {  
    @Override  
    public void run() {  
        while (true) {  
            synchronized (Desk.lock) {  
                if (Desk.count == 0) { //桌子上的食物做够了  
                    break;  
                }else{  
                    //判断是否有食物  
                    if(Desk.foodFlag == 1){ //如果有食物 等待消费者来吃  
                        try {  
                            Desk.lock.wait();  
                        } catch (InterruptedException e) {  
                            throw new RuntimeException(e);  
                        }  
                    }else{  
                        //如果没有食物 做  
                        //修改食物状态  
                        System.out.println("厨师做了一碗面条");  
                        Desk.foodFlag = 1;  
                        //叫醒消费者吃  
                        Desk.lock.notifyAll();  
                    }  
                }  
            }  
        }  
    }  
}

Foodie:消费者

package 生产者消费者;  
public class Foodie extends Thread{  
    @Override  
    public void run() {  
        while(true){  
            synchronized (Desk.lock){  
                if(Desk.count == 0){ //桌子上的食物做够了  
                    break;  
                }else {  
                    //判断桌子上有没有面条  
                    if(Desk.foodFlag ==  0){  
                        //如果没有 就等待  
                        try {  
                            Desk.lock.wait(); //让线程等待  
                        } catch (InterruptedException e) {  
                            throw new RuntimeException(e);  
                        }  
                    }else{ //如果有 直接开吃  
                        Desk.count--;  
                        System.out.println("吃货吃了一碗,还剩" + Desk.count + "碗!");  
                        //唤醒厨师! 份数-1  
                        Desk.lock.notifyAll();  
                        //修改桌子的状态  
                        Desk.foodFlag = 0;  
                    }  
                }  
            }  
        }  
    }  
}

阻塞队列方式

image.png
实现类:
ArrayBlockingQueue
LinkedBlockingQueue

队列和链表自带锁

线程的状态

七大状态:
image.png

线程中的栈

image.png

当在run方法中创建了一个集合,那么每一个线程都会维持一个创建的集合(类似于static)

线程池

image.png

image.png

image.png

代码:
image.png

自定义线程池

image.png
image.png

最大并行数

  • 什么是最大并行数?
    就是电脑的核心处理单元和线程,这里是八核十六线程
    image.png

image.png

计算类型多:

image.png
读取文件或者数据库比较多:
image.png

  • 32
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
黑马程序员线程练习题主要包括两个问题。第一个问题是如何控制四个线程在打印log之前能够同时开始等待1秒钟。一种解决思路是在线程的run方法中调用parseLog方法,并使用Thread.sleep方法让线程等待1秒钟。另一种解决思路是使用线程池,将线程数量固定为4个,并将每个调用parseLog方法的语句封装为一个Runnable对象,然后提交到线程池中。这样可以实现一秒钟打印4行日志,4秒钟打印16条日志的需求。 第二个问题是如何修改代码,使得几个线程调用TestDo.doSome(key, value)方法时,如果传递进去的key相等(equals比较为true),则这几个线程应互斥排队输出结果。一种解决方法是使用synchronized关键字来实现线程的互斥排队输出。通过给TestDo.doSome方法添加synchronized关键字,可以确保同一时间只有一个线程能够执行该方法,从而实现线程的互斥输出。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [黑马程序员——多线程10:多线程相关练习](https://blog.csdn.net/axr1985lazy/article/details/48186039)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值