• 20190312_浅谈go&java差异(一)


    多线程

    • java

    java中对于大量的比较耗时的任务多采用多线程对方式对任务进行处理,同时由于进程和线程
    本身是通过宿主机OS进行管理的,当在cpu核数较少或线程分配不当 会导致多线程的效果不佳的事常有发生

    代码片段:

        //处理器核心数
        int processor = Runtime.getRuntime().availableProcessors();
        //XSSFWorkbook 一次只能写入六万多条数据,所以这里最好使用SXSSFWorkbook
        SXSSFWorkbook workBook = new SXSSFWorkbook();
        //创建格式
        CellStyle style = workBook.createCellStyle();
        //居中格式
        style.setAlignment(HorizontalAlignment.CENTER);
        //手工创建线程池
        ExecutorService executorService = new ThreadPoolExecutor(processor, processor, 1000, TimeUnit.MILLISECONDS, new LinkedBlockingDeque(),
                new ThreadFactoryBuilder().setNameFormat("poi-task-%d").build());
        //计数器 等待线程池中的线程执行完毕
        CountDownLatch countDownLatch = new CountDownLatch(processor);
        for (int i = 0; i < processor; i++) {
            int sheetId = i;
            //放入线程池中
            executorService.execute(() -> createSheet(workBook, style,sheetId, countDownLatch));
        }
        try {
            //等待所有线程执行完毕
            countDownLatch.await();
            executorService.shutdown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    
    • go

      由于进程和线程都是基于OS管理的,不可避免的产生开销;go区别与以上两者使用的是协程(goroutine),协程是线程的内的细颗粒化,
      同时它是被go自己管理的所以开销相当的小,同时一个go应用可以轻松构建上百万个goroutine,不仅如此,go也提供了通道(channel)方便
      对协程之间进行数据交互

    代码片段:

    import (
    	"fmt"
    	"sync"
    )
    
    func says(s string, gw *sync.WaitGroup) {
    	for i := 0; i < 5; i++ {
    		fmt.Println(">>> ", s)
    	}
    	gw.Done()
    }
    func main() {
    	var gw sync.WaitGroup
    	gw.Add(1)
    	go says("Hello s", &gw)
    	gw.Wait()
    }
    

    函数参数传递

    • java

    java对于函数值对传递采取对是值传递的方式,对于基本数据类型:传递前后值所在栈的位置是不一致的(也就是被拷贝了一份)
    对于非基本数据类型:虽然也会做拷贝,但实际上这前后的对象引用的是同一内存位置的值,这就造成了"引用传递的假象"

    代码片段:

    public class TransParams {
    
        public static void main(String[] args){
            Person p = new Person();
            p.setAge(99);
            p.setName("Lisa");
    
            System.out.println(p.getAge());
            System.out.println(p);
            System.out.println("======>split<=====");
    
            TransParams tp = new TransParams();
            tp.setValue(p);
            System.out.println(p.getAge());
            System.out.println(p);
        }
    
        public  void setValue(Person p){
            p.setAge(19);
        }
    }
    class Person {
        private Integer age;
        private String name;
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    

    运行结果:

       99
       com.task.charset.Person@7e0b37bc
       ======>split<=====
       19
       com.task.charset.Person@7e0b37bc
    
    • go

      go语言的处理方式不同于java,具体分两个种:拷贝传递 和 指针传递
      对于拷贝传递:不论是基本数据类型还是结构体类型,前后的值都不会是同一个
      对于引用传递:传递前后都是同一个值对象,不会存在java的理解歧义

      代码片段:

    import "fmt"
    
    func main() {
    	var s1 []string
    	fmt.Println("拷贝传递前>", s1)
    	tr01(s1)
    	fmt.Println("拷贝传递后>", s1)
    
    	fmt.Println("=====><=====")
    
    	var s2 []string
    	fmt.Println("指针传递前>", s2)
    	tr02(&s2)
    	fmt.Println("指针传递后>", s2)
    }
    
    func tr01(m []string) {
    	m = append(m, "youth01")
    }
    
    func tr02(mm *[]string) {
    	*mm = append(*mm, "youth02")
    }
    
    

    输出结果:

    拷贝传递前> []
    拷贝传递后> []
    =====><=====
    指针传递前> []
    指针传递后> [youth02]
    

    日期格式处理

    • java

    在java8之前jdk仅提供了Date类型的格式化,对应的日期处理类是SimpleDateFormat,
    在java8至java8之后Oracle提供了LocalDate与LocalDateTime的两种日期格式,对应的日期处理类是DateTimeFormat

    代码片段:

    public class Format2LocalDate {
        private static final Logger LOG = LoggerFactory.getLogger(Format2LocalDate.class);
    
        private static final DateTimeFormatter DATE_FORMAT_SHORT = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss");
    
        @Test
        public void transDate(){
            this.parse();
            this.format();
            LOG.info(".....................");
            this.parseD();
            this.formatD();
        }
        public void parse(){
            String str = "20190116 12:12:22";
            Date today = Date.from(LocalDateTime.parse(str,DATE_FORMAT_SHORT).atZone(DateUtil.CHINA_ZONE_ID).toInstant());
            LOG.info("转换结果为> {}",today);
        }
    
        public void format(){
            LocalDateTime ldt = LocalDateTime.now();
            LOG.info("格式化字符串> {}",ldt.format(DATE_FORMAT_SHORT));
    
        }
    
    
        public final static String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    
    
        public void parseD(){
            String dateStr = "2019-01-01 12:22:33";
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT);
            Date date = null;
            try {
                 date =  simpleDateFormat.parse(dateStr);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            LOG.info("转换结果为> {}",date);
        }
    
        public void formatD(){
            Date date = new Date();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT);
    
            LOG.info("格式化结果为> {}",simpleDateFormat.format(date));
    
        }
    }
    
    

    输出结果为:

    转换结果为> Wed Jan 16 12:12:22 CST 2019
    格式化字符串> 20190313 21:20:23
    .....................
    转换结果为> Tue Jan 01 12:22:33 CST 2019
    格式化结果为> 2019-03-13 21:20:23
    
    • go

      go的日期处理相对于java来说十分的怪异,官方给出的例子是个固定的日期字符串,并非"yyyymmdd"这种形式,这里就不用说了
      看代码

      代码片段:

    /**
      官方定义的不可更改
    */
    const DATE_FORMAT string = "2006-01-02 15:04:05"
    
    func main() {
    	parse()
    	format()
    }
    
    func parse() {
    	tm := time.Now()
    	strs := tm.Format(DATE_FORMAT)
    	fmt.Println("日期转换为字符串> ", strs)
    }
    func format() {
    	tm, _ := time.Parse(DATE_FORMAT, "2019-01-01 12:12:12")
    	fmt.Println("字符串转换为日期> ", tm)
    }
    

    运行结果:

    日期转换为字符串>  2019-03-13 21:29:30
    字符串转换为日期>  2019-01-01 12:12:12 +0000 UTC
    

    数学运算

    • java

      java的数学基本运算往往会有精度丢失问题,所以对于敏感运算建议使用BigDecimal
      代码片段:

    //加减乘除都出现了对应的精度问题
    public class MathCalcul {
        private static final Logger LOG = LoggerFactory.getLogger(MathCalcul.class);
    
        @Test
        public void calcul(){
            LOG.info("加: {}",0.1 + 0.2);
            LOG.info("减: {}",1.1 - 0.11);
            LOG.info("乘: {}",1.13 * 100);
            LOG.info("除: {}",100.13 / 100);
        }
    }
    
    

    输出结果:

    加: 0.30000000000000004
    减: 0.9900000000000001
    乘: 112.99999999999999
    除: 1.0012999999999999
    
    • go

      go 不存在精度丢失问题,可以看代码可知

    func main() {
    	fmt.Println("加: ", 0.1+0.2)
    	fmt.Println("减: ", 1.1-0.11)
    	fmt.Println("乘: ", 1.13*100)
    	fmt.Println("除: ", 100.13/100)
    }
    
    

    输出结果:

    加:  0.3
    减:  0.99
    乘:  113
    除:  1.0013
    

    http Server

    • java

      java的http Server是基于Servlet,应对高并发时的策略是多线程,处理效率一般
      代码示例:

    class MyServlet extends HttpServlet{
        private static final ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
    
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String protocol = req.getProtocol();
            String msg = lStrings.getString("http.method_get_not_supported");
            if (protocol.endsWith("1.1")) {
                resp.sendError(405, msg);
            } else {
                resp.sendError(400, msg);
            }
    
        }
    
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String protocol = req.getProtocol();
            String msg = lStrings.getString("http.method_post_not_supported");
            if (protocol.endsWith("1.1")) {
                resp.sendError(405, msg);
            } else {
                resp.sendError(400, msg);
            }
    
        }
    }
    
    
    • go

      go 源码是自带http包的,所以无需第三方封装,开发较为简单;应对高并发时的策略是多协程,处理效果较好
      代码示例:

    import (
    	"fmt"
    	"net/http"
    )
    
    func index_handle(w http.ResponseWriter, r *http.Request) {
    	fmt.Fprintf(w, "Whoa,Go is cool!")
    }
    func main() {
    	http.HandleFunc("/", index_handle)
    	http.ListenAndServe(":8000", nil)
    }
    
    

    常量与静态变量

    • java

      java 中常量(final) 与 静态(static) 是分开的,常量:只能动态赋值一次后不可改变 静态:类型不变
      示例:

    //静态
    public static String str  = "hello";
    //常量
    public final String str2 = "hello2";
    //不可变量(初始化后不可重新赋值)
    public static final String str3 = "hello3";
    
    • go

      go 没有静态一说,只有常量(const)一说,在初始化后不能改变,其实就相当于 java中的 final + static
      示例:

    const str string = "hello"
    

    本章就到这里吧,敬请期待下一讲。(^_^)

    现在是 2019-03-13 22:29:50,各位晚安~

  • 相关阅读:
    java基础
    Java开发环境搭建
    打开CMD的方式和常用的Dos命令
    电脑常用快捷键
    Markdown学习
    c# json object Dictionary互转
    dapper 跨表查询
    Dapper SimpleCRUD Demo
    c#中的常用ToString()方法总结
    android js 模拟键盘
  • 原文地址:https://www.cnblogs.com/funnyzpc/p/10527162.html
Copyright © 2020-2023  润新知