黑马全套Java教程(九):网络编程(二)

简介: 黑马全套Java教程(九):网络编程(二)

黑马全套Java教程(九):网络编程(一)+https://developer.aliyun.com/article/1556494

36.5 线程通信

线程通信就是线程间相互发送数据,线程通信通常通过共享一个数据的方式实现。

线程间会根据共享数据的情况决定自己该怎么做,以及通知其他线程怎么做

Account.java

package d7_thread_comunication;
public class Account {
    private String cardId;
    private double money; //账户余额
    public Account(){}
    public Account(String cardId, double money) {
        this.cardId = cardId;
        this.money = money;
    }
    public String getCardId() {
        return cardId;
    }
    public void setCardId(String cardId) {
        this.cardId = cardId;
    }
    public double getMoney() {
        return money;
    }
    public void setMoney(double money) {
        this.money = money;
    }
    public synchronized void drawMoney(double money){
        try {
            String name = Thread.currentThread().getName();
            if(this.money >= money){
                this.money -= money;
                System.out.println(name + "来取钱" + money + "成功!余额是:" + this.money);
                //没钱了
                this.notifyAll();  //唤醒所有线程
                this.wait();  //锁对象,让当前线程进入等待
            }else{
                //钱不够
                this.notifyAll();  //唤醒所有线程
                this.wait();  //锁对象,让当前线程进入等待
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    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.notifyAll();
                this.wait();
            }else{
                //有钱,不存钱
                this.notifyAll();
                this.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

DrawThread.java

package d7_thread_comunication;
/*
* 取钱的线程类
* */
public class DrawThread extends Thread{
    private Account acc;
    public DrawThread(Account acc, String name){
        super(name);
        this.acc = acc;
    }
    @Override
    public void run(){
        while(true){
            acc.drawMoney(100000);
            try{
                Thread.sleep(3000);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

DepositThread.java

package d7_thread_comunication;
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);
            try{
                Thread.sleep(3000);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

ThreadDemo.java

package d7_thread_comunication;
public class ThreadDemo {
    //目标:了解线程通信的流程
    public static void main(String[] args) {
        // 1. 创建账户对象,代表5个人共同的操作的账户
        Account acc = new Account("ICBC-112", 0);
        //2. 创建2个取钱线程
        new DrawThread(acc, "小明").start();
        new DrawThread(acc, "小红").start();
        new DepositThread(acc, "亲爹").start();
        new DepositThread(acc, "干爹").start();
        new DepositThread(acc, "岳父").start();
    }
}


36.6 线程池

线程池就是一个可以复用线程的技术。如果用户每发起一个请求,后台就创建一个新线程来处理,下次新任务来了又要创建新线程,而创建新线程的开销是很大的,这样会严重影响系统的性能。



临时线程什么时候创建:新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程。

什么时候会开始拒绝任务:核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始任务拒绝

ThreadPoolDemo1.java

package d8_threadpool;
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,
                6, 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.execute(target);
        //关闭线程池(开发中一般不会使用)
        //pool.shutdownNow();  //立即关闭,即使任务没有完成,丢失任务的
        pool.shutdown();  //会等待全部任务执行完毕之后再关闭
    }
}

MyRunnable.java

package d8_threadpool;
public class MyRunnable implements Runnable{
    @Override
    public void run(){
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "输出了:HelloWorld ==> " + i);
        }
        try{
            System.out.println(Thread.currentThread().getName() + "本任务与线程绑定了,线程进入休眠了");
            Thread.sleep(10000000);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}


例2:

ThreadPoolDemo2.java

package 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,
                6, 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));
        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());
    }
}

MyCallable.java

package d8_threadpool;
import java.util.concurrent.Callable;
//1. 定义一个任务类  实现Callable接口  应该声明线程任务执行完毕后的结果的数据类型
public 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 += i;
        }
        return Thread.currentThread().getName() + "执行1-" + n + "的和,结果是:" + sum;
    }
}


方法二:Executors创建线程池线程池

ThreadPoolDemo3.java

package d8_threadpool;
import java.util.concurrent.*;
//目标:使用Executors的工具方法直接得到一个线程池对象
public class ThreadPoolDemo3 {
    public static void main(String[] args) throws Exception{
        //1. 创建固定线程数据的线程池
        ExecutorService pool = Executors.newFixedThreadPool(3);
        pool.execute(new MyRunnable());
        pool.execute(new MyRunnable());
        pool.execute(new MyRunnable());
        pool.execute(new MyRunnable());   //已经没有多余线程了
    }
}


36.7 定时器

定时器是一种控制任务延时调用,或者周期调用的技术

作用:闹钟、定时邮件发送

定时器的实现方式:

方式一:Timer

方式二:ScheduledExecutorService

方法一:Timer定时器是单线程执行,会有问题

package d9_timer;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimerDemo1 {
    public static void main(String[] args) {
        //1. 创建Timer定时器
        Timer timer = new Timer();   //定时器本身就是一个单线程
        //2. 调用方法,处理定时任务
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行A  " + new Date());
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, 3000, 2000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行B  " + new Date());
            }
        }, 3000, 2000);
    }
}
Timer-0执行A  Sat Nov 05 20:47:33 CST 2022
Timer-0执行B  Sat Nov 05 20:47:38 CST 2022
Timer-0执行A  Sat Nov 05 20:47:38 CST 2022
Timer-0执行A  Sat Nov 05 20:47:43 CST 2022
Timer-0执行B  Sat Nov 05 20:47:48 CST 2022
Timer-0执行A  Sat Nov 05 20:47:48 CST 2022

方法二:ScheduledExecutorService定时器

例:线程池做定时器

package d9_timer;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class TimerDemo2 {
    public static void main(String[] args) {
        //1. 创建ScheduledExecutorService线程池,做定时器
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
        //2. 开启定时任务
        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行输出:AAA   " + new Date());
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, 0, 2, TimeUnit.SECONDS);   //2秒
        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行输出:BBB   " + new Date());
            }
        }, 0, 2, TimeUnit.SECONDS);   //2秒
    }
}

36.8 并发并行、生命周期

并发剑法

黑马全套Java教程(九):网络编程(三)+https://developer.aliyun.com/article/1556507

目录
相关文章
|
3月前
|
安全 网络协议 算法
Nmap网络扫描工具详细使用教程
Nmap 是一款强大的网络发现与安全审计工具,具备主机发现、端口扫描、服务识别、操作系统检测及脚本扩展等功能。它支持多种扫描技术,如 SYN 扫描、ARP 扫描和全端口扫描,并可通过内置脚本(NSE)进行漏洞检测与服务深度枚举。Nmap 还提供防火墙规避与流量伪装能力,适用于网络管理、渗透测试和安全研究。
507 1
|
4月前
|
JSON 移动开发 网络协议
Java网络编程:Socket通信与HTTP客户端
本文全面讲解Java网络编程,涵盖TCP与UDP协议区别、Socket编程、HTTP客户端开发及实战案例,助你掌握实时通信、文件传输、聊天应用等场景,附性能优化与面试高频问题解析。
|
4月前
|
Java 关系型数据库 数据库
Java 项目实战教程从基础到进阶实战案例分析详解
本文介绍了多个Java项目实战案例,涵盖企业级管理系统、电商平台、在线书店及新手小项目,结合Spring Boot、Spring Cloud、MyBatis等主流技术,通过实际应用场景帮助开发者掌握Java项目开发的核心技能,适合从基础到进阶的学习与实践。
531 3
|
2月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
177 1
|
2月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
203 1
|
3月前
|
安全 Java
Java之泛型使用教程
Java之泛型使用教程
257 10
|
2月前
|
Oracle Java 关系型数据库
Java 简单教程
Java是跨平台、面向对象的编程语言,广泛用于企业开发、Android应用等。本教程涵盖环境搭建、基础语法、流程控制、面向对象、集合与异常处理,助你快速入门并编写简单程序,为进一步深入学习打下坚实基础。
330 0
|
2月前
|
机器学习/深度学习 分布式计算 Java
Java与图神经网络:构建企业级知识图谱与智能推理系统
图神经网络(GNN)作为处理非欧几里得数据的前沿技术,正成为企业知识管理和智能推理的核心引擎。本文深入探讨如何在Java生态中构建基于GNN的知识图谱系统,涵盖从图数据建模、GNN模型集成、分布式图计算到实时推理的全流程。通过具体的代码实现和架构设计,展示如何将先进的图神经网络技术融入传统Java企业应用,为构建下一代智能决策系统提供完整解决方案。
332 0
|
5月前
|
缓存 安全 Java
Java 并发新特性实战教程之核心特性详解与项目实战
本教程深入解析Java 8至Java 19并发编程新特性,涵盖CompletableFuture异步编程、StampedLock读写锁、Flow API响应式流、VarHandle内存访问及结构化并发等核心技术。结合电商订单处理、缓存系统、实时数据流、高性能计数器与用户资料聚合等实战案例,帮助开发者高效构建高并发、低延迟、易维护的Java应用。适合中高级Java开发者提升并发编程能力。
157 0
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
527 1