20190312_淺談go&java差別(一)

多線程

  • java

java中對於大量的比較耗時的任務多采用多線程對方式對任務進行處理,同時因爲進程和線程
自己是經過宿主機OS進行管理的,當在cpu核數較少或線程分配不當 會致使多線程的效果不佳的事常有發生java

代碼片斷:多線程

//處理器核心數
    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)方便
    對協程之間進行數據交互app

代碼片斷:函數

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對於函數值對傳遞採起對是值傳遞的方式,對於基本數據類型:傳遞先後值所在棧的位置是不一致的(也就是被拷貝了一份)
對於非基本數據類型:雖然也會作拷貝,但實際上這先後的對象引用的是同一內存位置的值,這就形成了"引用傳遞的假象"高併發

代碼片斷:post

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;
    }
}

運行結果:ui

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

    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,各位晚安~

相關文章
相關標籤/搜索