黑马全套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

目录
相关文章
|
22天前
|
Java
【思维导图】JAVA网络编程思维升级:URL与URLConnection的逻辑梳理,助你一臂之力!
【思维导图】JAVA网络编程思维升级:URL与URLConnection的逻辑梳理,助你一臂之力!
33 1
|
22天前
|
XML JSON 搜索推荐
【高手过招】JAVA网络编程对决:URL与URLConnection的高级玩法,你敢挑战吗?
【高手过招】JAVA网络编程对决:URL与URLConnection的高级玩法,你敢挑战吗?
43 0
|
2天前
|
Java API
Java时间戳教程
本文详细介绍Java中时间戳的处理方法,包括获取当前时间戳、使用`java.time`包、时间戳与日期的相互转换及格式化等。示例代码展示了如何利用`System.currentTimeMillis()`和`java.time.Instant`获取时间戳,以及如何通过`Date`和`ZonedDateTime`进行日期转换和时区处理。随着Java 8引入的`java.time`包,日期时间操作变得更加强大和便捷,推荐在新项目中优先采用。
|
22天前
|
Java
【实战演练】JAVA网络编程高手养成记:URL与URLConnection的实战技巧,一学就会!
【实战演练】JAVA网络编程高手养成记:URL与URLConnection的实战技巧,一学就会!
29 3
|
22天前
|
安全 Java 网络安全
【认知革命】JAVA网络编程新视角:重新定义URL与URLConnection,让网络资源触手可及!
【认知革命】JAVA网络编程新视角:重新定义URL与URLConnection,让网络资源触手可及!
31 2
|
23天前
|
存储 算法 Java
Java中的集合框架深度解析云上守护:云计算与网络安全的协同进化
【8月更文挑战第29天】在Java的世界中,集合框架是数据结构的代言人。它不仅让数据存储变得优雅而高效,还为程序员提供了一套丰富的工具箱。本文将带你深入理解集合框架的设计哲学,探索其背后的原理,并分享一些实用的使用技巧。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇通往高效编程的大门。
|
24天前
|
编解码 网络协议 Oracle
java网络编程入门以及项目实战
这篇文章是Java网络编程的入门教程,涵盖了网络编程的基础知识、IP地址、端口、通讯协议(TCP和UDP)的概念与区别,并提供了基于TCP和UDP的网络编程实例,包括远程聊天和文件传输程序的代码实现。
java网络编程入门以及项目实战
|
21天前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
42 0
|
22天前
|
缓存 Java API
【技术前沿】JAVA网络编程黑科技:URL与URLConnection的创新应用,带你飞越极限!
【技术前沿】JAVA网络编程黑科技:URL与URLConnection的创新应用,带你飞越极限!
28 0
|
23天前
|
Java API
Java与Lua互相调用简单教程
【8月更文挑战第29天】在软件开发中,Java以其强大的稳定性和广泛的生态系统著称,而Lua则因其轻量级、灵活和嵌入式的特点在脚本编写、游戏开发等领域大放异彩。将两者结合使用,可以充分利用Java的底层能力和Lua的快速开发优势。本文将通过一个简单的教程,介绍如何在Java程序中嵌入并执行Lua脚本,以及如何在Lua中调用Java方法。
19 0