多线程编码-发送邮件(go和java 实现)
多线程编码-发送邮件(go和java 实现)
发送邮件
我的一个简单的 思维导图 https://www.processon.com/mindmap/5f8a9fcc07912906db2cd5af
简单来讲,就是线程之间数据交互的问题
简单的时序图如下:(时序图这个东西就是一个随着时间线往下走的)
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 发送文件到