三则案例,助你掌握多线程 | 带你学《Java语言高级特性》之十五

简介: 经历了前几节的学习,相信你已经对多线程有了自己的见解,现在,跟作者一起实操三则案例,助你快速消化所学知识吧!

上一篇:另类的“同步”-volatile关键字 | 带你学《Java语言高级特性》之十四
【本节目标】
通过阅读本节内容,你将通过数字加减、生产电脑、竞争抢答三则案例的多线程相关逻辑实现,进一步掌握多线程开发的相关能力,对线程的各类操作更加得心应手。

多线程案例分析一:数字加减

设计4个线程对象,两个线程执行减操作,两个线程执行加操作。

public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        Resource res = new Resource();
        SubThread st = new SubThread(res);
        AddThread at = new AddThread(res);
        new Thread(at, "加法线程-A ").start();
        new Thread(at, "加法线程-B ").start();
        new Thread(st, "减法线程-X ").start();
        new Thread(st, "减法线程-Y ").start();
    }
}
class AddThread implements Runnable {
    private Resource resource;
    public AddThread(Resource resource) {
        this.resource = resource;
    }
    @Override
    public void run() {
        for (int x = 0 ; x< 50 ; x++) {
            try {
                this.resource.add();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
class SubThread implements Runnable {
    private Resource resource;
    public SubThread(Resource resource) {
        this.resource = resource;
    }
    @Override
    public void run() {
        for (int x = 0 ; x < 50 ; x++) {
            try {
                this.resource.sub();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
class Resource {     //定义一个操作的资源
    private int num = 0;      //这个是要进行加减操作的数据
    private boolean flag = true;       //加减的切换
    //flag = true:表示可以进行加法操作,但是无法进行减法操作
    //flag = false:表示可以进行减法操作,但是无法进行加法操作
    public synchronized void add() throws Exception {      //执行加法操作
        if (this.flag == false) {         //现在需要执行的是减法操作,加法操作要等待
            super.wait();
        }
        Thread.sleep(100) ;
        this.num++ ;
        System.out.println("【加法操作 -" + Thread.currentThread().getName() + "】num = " + this.num) ;
        this.flag = false ;    //加法操作执行完毕,需要执行减法处理
        super.notifyAll() ;   //唤醒全部等待线程

    }
    public synchronized void sub() throws Exception {    //执行减法操作
        if (this.flag == true) {      //减法操作需要等待
            System.out.println("【减法操作 -" + 
Thread.currentThread().getName() + "】进行等待") ;
            super.wait() ;
        }
        Thread.sleep(200) ;
        this.num-- ;
        System.out.println("【减法操作 -" + Thread.currentThread().getName() + "】num = " + this.num) ;
        this.flag = true ;
        super.notifyAll() ;
    }
}

image.png
图一 多线程加减法操作

这是一个经典的多线程开发操作,这一个程序里面一定要考虑的核心本质在于:加一个、减一个,整体的计算结果应该在0、-1、1 中循环出现才是合理的。

多线程案例分析二:生产电脑

设计一个生产电脑和搬运电脑类,要求生产出一台电脑就搬走一台电脑,如果没有新的电脑生产出来,则搬运工需要等待新电脑产出;如果生产出的电脑没有搬走,则要等待电脑搬走再生产,并统计出生产的电脑数量。
在本程序中,就是一个标准的生产者与消费者的处理模型,那么下面实现具体的程序代码。

public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        Resource res = new Resource() ;
        new Thread(new Producer(res)).start() ;
        new Thread(new Consumer(res)).start() ;
        new Thread(st).start() ;
        new Thread(st).start() ;
    }
}
class Producer implements Runnable {
    private Resource resource ;
    public Producer(Resource resource) {
        this.resource = resource ;
    }
    @Override
    public void run() {
        for (int x = 0; x < 50; x++) {
            try {
                this.resource.make() ;
            } catch (Exception e) {
                e.printStackTrace() ;
            }
        }
    }
}
class Consumer implements Runnable {
    private Resource resource ;
    public Consumer(Resource resource) {
        this.resource = resource ;
    }
    @Override
    public void run() {
        for (int x = 0 ; x < 50 ; x++) {
            try {
                this.resource.get() ;
            } catch (Exception e) {
                e.printStackTrace() ;
            }
        }
    }
}
class Resource {
    private Computer computer ;
    private boolean flag = true ;         //标记
    public synchronized void make() throws Exception {
        if (this.computer != null) {   //已经生产过了
            super.wait() ;
        }
        Thread.sleep(100) ;
        this.computer = new Computer("MLDN牌电脑", 1.1) ;
        System.out.println("【生产电脑】"+ this.computer) ;
        super.notifyAll() ;
    }
    public synchronized void get() throws Exception {
        if (this.computer == null) {    //没有生产过
            super.wait() ;
        }
        Thread.sleep(10) ;
        System.out.println("【取走电脑】"+ this.computer) ;
        this.computer = null ;    //已经取走了
        super.notifyAll() ;
    }
}
class Computer {
    private static int count = 0 ;    //表示生产的个数
    private String name ;
    private double price ;
    public Computer(String name, double price) {
        this.name = name ;
        this.price = price ;
        count++ ;
    }
    public String toString() {
        return "【第" + count + "台电脑】电脑名字:" + this.name + "价值:" + this.price ;
    }
}

image.png
图二 实现生产电脑

多线程案例分析三:竞争抢答

实现一个竞拍抢答程序:要求设置三个抢答者(三个线程),而后同时发出抢答指令,抢答成功者给出成功提示,未抢答成功者给出失败提示。

对于这个多线程操作,由于里面需要牵扯到数据返回问题,那么现在最好使用Callable是比较方便的一种处理形式。

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        FutureTask<String> taskA = new FutureTask(mt);
        FutureTask<String> taskB = new FutureTask(mt);
        FutureTask<String> taskC = new FutureTask(mt);
        new Thread(taskA, "竞赛者A").start();
        new Thread(taskB, "竞赛者B").start();
        new Thread(taskC, "竞赛者C").start();
        System.out.println(taskA.get());
        System.out.println(taskB.get());
        System.out.println(taskC.get());
    }
}
class MyThread implements Callable<String> {
    private boolean flag = false;          //抢到处理
    @Override
    public String call() throws Exception {
        synchronized (this) {                //数据同步
            if (this.flag == false) {        //抢答成功
                this.flag = true;
                return Thread.currentThread().getName() + "抢答成功!" ;
            } else {
                return Thread.currentThread().getName() + "抢答失败!" ;
            }
        }
    }
}

image.png
图三 多线程竞答

想学习更多的Java的课程吗?从小白到大神,从入门到精通,更多精彩不容错过!免费为您提供更多的学习资源。
本内容视频来源于阿里云大学

下一篇:让String拥有变化之力 | 带你学《Java语言高级特性》之十六
更多Java面向对象编程文章查看此处

相关文章
|
1天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
3天前
|
安全 Java
在 Java 中使用实现 Runnable 接口的方式创建线程
【10月更文挑战第22天】通过以上内容的介绍,相信你已经对在 Java 中如何使用实现 Runnable 接口的方式创建线程有了更深入的了解。在实际应用中,需要根据具体的需求和场景,合理选择线程创建方式,并注意线程安全、同步、通信等相关问题,以确保程序的正确性和稳定性。
|
1天前
|
缓存 Java 调度
Java中的多线程编程:从基础到实践
【10月更文挑战第24天】 本文旨在为读者提供一个关于Java多线程编程的全面指南。我们将从多线程的基本概念开始,逐步深入到Java中实现多线程的方法,包括继承Thread类、实现Runnable接口以及使用Executor框架。此外,我们还将探讨多线程编程中的常见问题和最佳实践,帮助读者在实际项目中更好地应用多线程技术。
9 3
|
3天前
|
监控 安全 Java
Java多线程编程的艺术与实践
【10月更文挑战第22天】 在现代软件开发中,多线程编程是一项不可或缺的技能。本文将深入探讨Java多线程编程的核心概念、常见问题以及最佳实践,帮助开发者掌握这一强大的工具。我们将从基础概念入手,逐步深入到高级主题,包括线程的创建与管理、同步机制、线程池的使用等。通过实际案例分析,本文旨在提供一种系统化的学习方法,使读者能够在实际项目中灵活运用多线程技术。
|
1天前
|
Java 关系型数据库 数据库
面向对象设计原则在Java中的实现与案例分析
【10月更文挑战第25天】本文通过Java语言的具体实现和案例分析,详细介绍了面向对象设计的五大核心原则:单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则帮助开发者构建更加灵活、可维护和可扩展的系统,不仅适用于Java,也适用于其他面向对象编程语言。
8 2
|
1天前
|
缓存 安全 Java
Java中的多线程编程:从基础到实践
【10月更文挑战第24天】 本文将深入探讨Java中的多线程编程,包括其基本原理、实现方式以及常见问题。我们将从简单的线程创建开始,逐步深入了解线程的生命周期、同步机制、并发工具类等高级主题。通过实际案例和代码示例,帮助读者掌握多线程编程的核心概念和技术,提高程序的性能和可靠性。
8 2
|
2天前
|
Java
Java中的多线程编程:从基础到实践
本文深入探讨Java多线程编程,首先介绍多线程的基本概念和重要性,接着详细讲解如何在Java中创建和管理线程,最后通过实例演示多线程的实际应用。文章旨在帮助读者理解多线程的核心原理,掌握基本的多线程操作,并能够在实际项目中灵活运用多线程技术。
|
4天前
|
Java 数据处理 开发者
Java多线程编程的艺术:从入门到精通####
【10月更文挑战第21天】 本文将深入探讨Java多线程编程的核心概念,通过生动实例和实用技巧,引导读者从基础认知迈向高效并发编程的殿堂。我们将一起揭开线程管理的神秘面纱,掌握同步机制的精髓,并学习如何在实际项目中灵活运用这些知识,以提升应用性能与响应速度。 ####
20 3
|
2天前
|
Java 开发者
Java中的多线程基础与应用
【10月更文挑战第24天】在Java的世界中,多线程是提高效率和实现并发处理的关键。本文将深入浅出地介绍如何在Java中创建和管理多线程,以及如何通过同步机制确保数据的安全性。我们将一起探索线程生命周期的奥秘,并通过实例学习如何优化多线程的性能。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开一扇通往高效编程的大门。
8 0
|
4天前
|
监控 安全 Java
在 Java 中使用线程池监控以及动态调整线程池时需要注意什么?
【10月更文挑战第22天】在进行线程池的监控和动态调整时,要综合考虑多方面的因素,谨慎操作,以确保线程池能够高效、稳定地运行,满足业务的需求。
71 38