java 多线程 发邮件,多线程编码-发送邮件(go和java 实现)

多线程编码-发送邮件(go和java 实现)

多线程编码-发送邮件(go和java 实现)

发送邮件

我的一个简单的 思维导图 https://www.processon.com/mindmap/5f8a9fcc07912906db2cd5af

简单来讲,就是线程之间数据交互的问题

简单的时序图如下:(时序图这个东西就是一个随着时间线往下走的)

6af3b8a0c8bb65c708eaa81355d7d0ab.png

go天生就支持并发,chan就是在协程之间同步数据的。

/**

go 的主函数的包名必须为 main

*/

package main

import (

"log"

"strconv"

"sync"

"time"

)

/**

主启动类

*/

func main() {

//创建 一个接耦类

m := new(MainBox)

//调用初始化函数,

m.Init()

//创建4个消息的接受者。go 关键字 表示开启线程。

for i := 0; i < 4; i++ {

go func() {

//m的create方法 返回一个box ,则此线程就从此box读取数据

create := m.Create()

receiver(create)

}()

}

//主线程sleep 1 秒,

time.Sleep(time.Second * 1)

log.Println("开始发送消息")

//得到中间解耦类map的所有的key

ids := m.GetAllId()

//遍历所有的key,来开启线程来做。

for index, id := range ids {

/**

请注意这里的赋值操作,

因为 在循环体中开启线程是不能引用循环体中的变量的,得重新赋值一个变量,否则就只有拿到最后的值。

*/

i := index

d := id

//开启发送者线程

go func() {

b := m.Get(d)

message := "消息" + strconv.Itoa(i)

log.Print("发送的消息为 -------->:", message)

b

}()

}

//主线程等待,要注意,在go中主线程有绝对的控制权,主线程如果结束,一切都会over

time.Sleep(time.Hour * 10)

}

//接受消息,此方法就是从 通道用拿数据。注意,此处的通道是没有缓存的通道,异步通道。

func receiver(box2 box) {

boxf :=

log.Print("收到的值:", boxf)

}

//声明 box类型,他的实际类型为 存放string 的chan

type box chan string

//中间结耦类

type MainBox struct {

//维护的map,key:自增需要,map:维护的 通道

chanMap map[int]box

//key的自增序号

sid int

//互斥锁

sync.Mutex

}

/**

得到id的自增序列

*/

func (this *MainBox) getId() int {

this.sid = this.sid + 1

return this.sid

}

//这是我自己写的初始化函数,用来初始化

func (this *MainBox) Init() {

//创建一个 map

this.chanMap = make(map[int]box)

//设置自增序列为的初始值为0

this.sid = 0

}

//得到一个 chan

func (this *MainBox) Create() box {

//lock不支持重入

this.Lock()

//在函数的最后调用 defer修饰的函数

defer this.Unlock()

//创造一个box

strings := make(box)

//得到一个自增序列

id := this.getId()

//设置kv

this.chanMap[id] = strings

return strings

}

/**

根据id拿到一个chan

*/

func (this *MainBox) Get(key int) box {

//这里加锁是因为多个协程要访问同一个共享变量。

this.Lock()

defer this.Unlock()

strings := this.chanMap[key]

//从map中删除 ,通过key

delete(this.chanMap, key)

return strings

}

/**

得到map的所有key,要通过key才能拿到chan

*/

func (this *MainBox) GetAllId() []int {

ints := make([]int, 0)

for i, _ := range this.chanMap {

ints = append(ints, i)

}

return ints

}

//init函数,是go中在使用包之前会默认调用的函数。

//这里就是设置日志的打印方式,go提供了简单的日志

func init() {

log.SetFlags(log.Lshortfile)

}

主测试类

package threadTest.postman;

import java.io.IOException;

import java.util.Set;

import java.util.concurrent.TimeUnit;

/**

* @program: jdk8Test

* @description: 主测试类

* @author: lc

* @date: 2020/10/17

**/

public class MainApplication {

public static void main(String[] args) throws InterruptedException, IOException {

System.out.println("receive start");

//得到中间接耦类

MainBox mainBox = new MainBox<>();

for (int i = 0; i < 4; i++) {

//创建接受者线程

ChanThread box = mainBox.createBox();

//将消息通道给接受者

Receive receive = new Receive(box);

receive.start();

}

//主线程睡眠1秒

TimeUnit.SECONDS.sleep(1);

System.out.println("postman start");

//得到接耦类的所有的id

Set ids = mainBox.getAllIds();

//遍历id创建发送者线程

for (Integer id : ids) {

int a = id;

ChanThread box = mainBox.getBoxById(id);

PostMan postMan = new PostMan(box, a);

postMan.start();

}

//主线程堵塞,方式死亡

System.in.read();

}

}

//发送者线程

class PostMan extends Thread{

private ChanThread chanThread;

private int id;

public PostMan(ChanThread chanThread,int id){

this.chanThread = chanThread;

this.id = id;

}

//重写run方法

@Override

public void run() {

try {

//通过通道发送消息

chanThread.push("message" + id);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

//接受者线程

class Receive extends Thread{

private ChanThread chanThread;

public Receive(ChanThread chanThread){

this.chanThread = chanThread;

}

@Override

public void run() {

try {

//通过线程接受消息

System.out.println(chanThread.take());

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

中间解耦类

package threadTest.postman;

import java.util.Map;

import java.util.Set;

import java.util.concurrent.ConcurrentHashMap;

/**

* @program: jdk8Test

* @description: 中间耦合类

* @author: lc

* @date: 2020/10/17

**/

public class MainBox {

private Map map;

private int count;

public MainBox() {

this.map = new ConcurrentHashMap<>(10);

this.count = 0;

}

public synchronized int getCount(){

return count++;

}

public ChanThread createBox(){

ChanThread tChanThread = new ChanThread(1);

map.put(getCount(), tChanThread);

return tChanThread;

}

public ChanThread getBoxById(int id){

return map.get(id);

}

public Set getAllIds(){

return map.keySet();

}

}

线程通道类

package threadTest.postman;

import java.util.ArrayList;

import java.util.List;

/**

* @program: jdk8Test

* @description: 线程同步通道

* @author: lc

* @date: 2020/10/17

**/

public class ChanThread {

//存放消息的list

private List messageList;

//消息的大小

private int size;

public ChanThread(int size) {

this.messageList = new ArrayList(size);

this.size = size;

}

//放消息

public void push(T obj) throws InterruptedException {

synchronized (this) {

//队列里面的消息已满,

while (messageList.size() > size){

//唤醒消费线程消费

this.notifyAll();

//自己堵塞

this.wait();

}

//环境消费线程消费,因为刚开始上来,消费线程都是在阻塞的。

this.notifyAll();

//添加消息进队列

messageList.add(obj);

}

}

//拿消息

public T take() throws InterruptedException {

synchronized (this){

//消息队列没有消息

while (messageList.isEmpty()){

//唤醒发送者发送消息

this.notifyAll();

//自己等待

this.wait();

}

//删除消息

return messageList.remove(messageList.size()-1);

}

}

}

看的出来 go的多线程还是比较简单灵活的。java 出来的太早了,那个时候硬件还不行,java出来就是单线程的那种。不像go,go出现的时候比价晚,硬件已经很好了。 go天生高并发

多线程编码-发送邮件(go和java 实现)相关教程

贪心-哈夫曼树,哈夫曼编码

贪心-哈夫曼树,哈夫曼编码 哈夫曼树定义和构造算法 2叉哈夫曼树 节点定义 建树,同时也是贪心算法的构造性证明 获取字符集的编码 用建好的2叉哈夫曼树对同一字符集的数据编码和解码 271. 字符串的编码与解码 $1 哈夫曼树 平衡树插入删除效率高的前提 各个节点

第八十五课、多线程与界面组件的通信(下)------------------狄

第八十五课、多线程与界面组件的通信(下)------------------狄泰软件学院 一、多线程与界面组件的通信 1、子线程更改界面组件状态的本质 (1)、子线程发射信号通知主线程界面更新请求 (2)、主线程根据具体信号以及信号参数对界面组件进行修改 2、另一种

java.net.HttpURLConnection发送POST、GET请求

java.net.HttpURLConnection发送POST、GET请求 请求测试: 引用POM: dependency groupIdorg.json/groupId artifactIdjson/artifactId version20180130/version/dependency 代码实现: import org.apache.http.HttpStatus;import org.springframework.stereoty

?线程池为什么可以复用,我是蒙圈了。。。

?线程池为什么可以复用,我是蒙圈了。。。 本章目录 一、线程池状态 二、execute源码 三、addworker源码 四、Worker源码 五、runworker源码 六、getTask源码 七、总结 八、题外话 看了源码才知道,我还是太菜了。。 一、线程池状态 首先我们要明确线程池的几

Jenkins试用总结(3) ----jenkins自动发送部署邮件

Jenkins试用总结(3) ----jenkins自动发送部署邮件 前两篇已经基本可以达到使用jenkins的要求了,现在我们提交代码jenkins就会帮你部署到服务器,这一篇主要学习jenkins把部署的结果发给用户 jenkins本身是自带一个邮件发送的,不过我并没有使用,我直接使

格雷编码 - 二进制 - 递归 - python javascript

格雷编码 - 二进制 - 递归 - python javascript leetcode:89题 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异。 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列。即使有多个不同答案,你也只需要返回其中一种。 格

同步类容器和并发类容器

同步类容器和并发类容器 ** ** 同步类容器都是线程安全的,同步容器类包括 Vector 和 HashTable,二者都是早期 JDK 的一部分,此外还包括在 JDK1.2 当中添加的一些功能相似的类,这些同步的封装类是由 Collections.synchronizedXxx 等工厂方法创建的。 但在某

jquery的ajax发送文件

jquery的ajax发送文件 ajax的post() 方法通过 HTTP POST 请求从服务器载入数据。 语法 jQuery.post(url,data,success(data, textStatus, jqXHR),dataType) 引用jquery: script src=https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js/script 发送文件到

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值