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

目录
相关文章
|
1天前
|
XML 测试技术 数据格式
《手把手教你》系列基础篇(八十五)-java+ selenium自动化测试-框架设计基础-TestNG自定义日志-下篇(详解教程)
【7月更文挑战第3天】TestNG教程展示了如何自定义日志记录。首先创建一个名为`TestLog`的测试类,包含3个测试方法,其中一个故意失败以展示日志。使用`Assert.assertTrue`和`Reporter.log`来记录信息。接着创建`CustomReporter`类,继承`TestListenerAdapter`,覆盖`onTestFailure`, `onTestSkipped`, 和 `onTestSuccess`,在这些方法中自定义日志输出。
18 6
|
19小时前
|
Java 测试技术 Apache
《手把手教你》系列基础篇(八十六)-java+ selenium自动化测试-框架设计基础-Log4j实现日志输出(详解教程)
【7月更文挑战第4天】Apache Log4j 是一个广泛使用的 Java 日志框架,它允许开发者控制日志信息的输出目的地、格式和级别。Log4j 包含三个主要组件:Loggers(记录器)负责生成日志信息,Appenders(输出源)确定日志输出的位置(如控制台、文件、数据库等),而 Layouts(布局)则控制日志信息的格式。通过配置 Log4j,可以灵活地定制日志记录行为。
13 4
|
1天前
|
网络协议 安全 Java
Java中的网络编程:Socket编程详解
Java中的网络编程:Socket编程详解
|
1天前
|
安全 网络协议 Java
Java中的网络通信:HTTP详解
Java中的网络通信:HTTP详解
|
1天前
|
网络协议 Java 网络安全
Java中的网络编程:TCP详解
Java中的网络编程:TCP详解
|
19小时前
|
网络协议 安全 Java
深入了解Java中的网络编程与Socket通信
深入了解Java中的网络编程与Socket通信
|
1天前
|
Linux 网络安全 数据安全/隐私保护
网络安全教程-------渗透工具Kali,官网链接,ARM的介绍,Mobil,华为小米,oppe手机,是无法刷入第三方的操作系统的,E+手机,谷歌的picksoul,或者三星手机,系统盘是WSL的
网络安全教程-------渗透工具Kali,官网链接,ARM的介绍,Mobil,华为小米,oppe手机,是无法刷入第三方的操作系统的,E+手机,谷歌的picksoul,或者三星手机,系统盘是WSL的
|
2天前
|
Java 测试技术 Android开发
《手把手教你》系列基础篇(八十四)-java+ selenium自动化测试-框架设计基础-TestNG日志-上篇(详解教程
【7月更文挑战第2天】TestNG是一个用于自动化测试的Java框架,提供日志记录功能。日志有两种模式:底层级详细记录每个步骤,高层级仅记录关键事件。示例代码展示了如何在测试方法中使用`Reporter.log()`记录信息,这些信息会显示在TestNG HTML报告中。文章还提及了日志显示时可能出现的编码问题及解决办法。
|
2天前
|
网络协议 Java
Java网络编程基础与Socket实现技术
Java网络编程基础与Socket实现技术
|
网络协议 Java API

热门文章

最新文章