特斯拉新款可能推 Model S 超跑版本 3秒加速至 96 公里

美國電動車商特斯拉 (Tesla) 即將在美國時間 10 月 9 日召開媒體大會,發表與字母「D」有關的神秘商品。特斯拉執行長 Elon Musk 一週前透過 Twitter 揭露相關訊息後,現在又再度透露了一點線索。   Vanity Fair 報導,Musk 8 日表示,特斯拉即將發表的神秘商品其實早就現身,只是人們都還沒有意識到而已。他說,網友非常會猜,方向大致都正確,但大家都還沒有意識到規模有多大。   Musk 的說法實在太過含糊,但最新的網路謠言也許可以讓大家稍稍解惑。Electrek 9 日引述訊息人士報導,特斯拉會在 9 日的大會上發表「P85D」,這是「Model S」的超跑版本,只要花 3 秒鐘就可把時速從零加快到 60 英里 (大約 96 公里),速度非常驚人。   根據報導,如此的表現已超越布卡堤 (Bugattis)、藍寶堅尼 (Lamborghinis)、麥拿倫 (Mclarens)、法拉利 (Ferraris)、保時捷 (Porsches) 等市面上最高級的超跑車種。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

F-英瑞搭電動車商機 下一步瞄準特斯拉

北美汽車水箱龍頭大廠英瑞國際 F-英瑞 9月受惠出貨成長,單月營收為 3.3 億元,累計前 9 月營收為 36.85 億元,年增 14.65%,英瑞看好電動車市場,攜手美國大廠合作開發新世代電動貨卡 (pick up),首年訂單銷售將達數萬台,下一步將接觸 TESLA,全面衝刺電動車市場。   F-英瑞第三季單季營收達到 11.13 億元,年增 1.64%,公司表示,北美車市持續改善,帶動 AM 市場成長,公司目前供應多家美國大型連鎖通路訂單,帶動今年成長,目前中國市場已經開始進入暖身階段,預計 2015 年中國市場也將成為另一成長引擎,公司看好明年在北美、中國兩大成長帶動下,營運將會水漲船高。   且為進軍電動車市場,F-英瑞將與美國大廠合作開發新世代電動貨卡,由於新款設計採用汽油發電來帶動運轉,整體續航力可以超過 600 公里,客戶對銷售相當樂觀,預計第 1 年銷售量就可以達到數萬台,由於電動車需要 4 套的冷卻系統,是一般車輛的 4 倍,因此業績將會倍數成長,下一階段將會將會接觸 Tesla,全面衝刺電動車市場。   除了中國、北美市場成長之外,F-英瑞也積極布局現在市佔率偏低的歐洲市場,由於全球汽車市場的成長,公司將積極規畫新產能,預計 2015 年將於東協設廠規劃 200 萬年產能的新廠。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

※教你寫出一流的銷售文案?

關於對Entity Framework Core3.1的理解與總結

Entity Framework Core 是一個ORM,所謂ORM也是ef的一個框架之一吧,簡單的說就是把C#一個類,映射到數據庫的一個表,把類裏面的屬性映射到表中的字段。然後Entity Framework Core3.1 是一個長期支持的版本。本人非常樂意對.NET社區繁榮奉獻自己的青春。希望國內以後能夠有越來越多的.NET程序員。

創建了一個.NET Standard類庫。

可以編輯文件查看netStandard版本號,我這裡是一個2.0版本。

順便簡單的說一下netStandard吧,實際上它應該就是一個開源庫,不管是.NET Core還是EntityFramework都可以引用它。就是一個底層類庫,並且該類庫可以在不同的平台運行,ios、mac、linux等。一處編寫多處運行,而且它還是開源的。當然這裏你可以把它改成2.1的版本。

 右鍵項目屬性

這樣就該好了。。。

然後又創建了一個類庫,操作和上面一樣,另一個是創建一個控制台應用,這個控制台應用是.NET Core應用的,版本應該是netcoreapp3.1,可以看看

以上準備工作完成后,就開始進行第一步操作,生成數據庫!

在Demo.Main類庫中創建所需要的類

這裏我就簡單的舉個栗子。一個聯賽類,一個是俱樂部類,一個是球員類,分別是一對多的關係。

namespace Demo.Main
{
    /// <summary>
    /// 聯賽
    /// </summary>
    public class League
    {
        public int  Id { get; set; }
        public string Name { get; set; }
        public string Country { get; set; }
    }
}
using System;
using System.Collections.Generic;

namespace Demo.Main
{
    /// <summary>
    /// 俱樂部
    /// </summary>
    public class Club
    {
        public Club()
        {
            Players=new List<Player>();//以防出現空指針引用
        }
        public int Id { get; set; }
        public string Name { get; set; }
        public string City { get; set; }
        /// <summary>
        /// 俱樂部成立日期
        /// </summary>
        public DateTime Establishment { get; set; }
        public string History { get; set; }
        /// <summary>
        /// 聯賽導航屬性
        /// </summary>
        public League League { get; set; }
        /// <summary>
        /// 一對多,一個俱樂部有多個球員
        /// </summary>
        public List<Player> Players { get; set; }
    }
}
using System;

namespace Demo.Main
{
    /// <summary>
    /// 球員
    /// </summary>
    public class Player
    {
        public int Id { get; set; }
        public string Name { get; set; }
        /// <summary>
        /// 球員出生日期
        /// </summary>
        public DateTime DateOfBirth { get; set; }
    }
}

然後就是在Data中引用Main的項目庫

對Data類庫安裝對數據庫操作的相關依賴,也就是方便對Model映射到數據庫。顯而易見,Data類庫就是操作對Model映射到數據的Code first數據庫遷移操作的。

所以必然是少不了上下文類的編寫和操作了。

接下來就是準備遷移操作了,但是對於Demo.Data類庫來說它是一個底層的類庫,所以我們就得通過Demo.App一個控制台應用來去生成數據庫,然後就要通過NuGet包進行一個引用了。

需要對數據庫操作進行可執行文件的操作需要引用一下依賴吧可以說是

這個就裝在Demo.Data項目中

這裏就可以看到它為什麼對數據庫遷移起到作用了

點擊下載即可,而後才能執行數據庫遷移操作

記得在遷移時一定要選擇上下文存在的類的項目也就是Data

然後就是用命令來操作包管理工具了,來具體總結一下吧!

你可以通過給的提示輸入命令也就是get-help NuGet查看具體的一些幫助命令

主要命令應該就是這些,具體解釋可以再去看看

或者輸入get-help entityframework,結果如下,我們用到的就是Add-Migration(添加遷移)、Update-Database(更新數據庫)這兩個應該就是比較常用的了。

輸入第一個命令 Add-Migration 這裏需要給個參數(實際上有很多參數)這個參數就是會在生成的時間戳後面定義的Name參數

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

Spring7——開發基於註解形式的spring

開發基於註解形式的spring
SpringIOC容器的2種形式:
(1)xml配置文件:applicationContext.xml; 存bean:<bean> 取bean:

ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");

(2)註解:帶有@Configuration註解的類(配置類)

存bean:@Bean+方法的返回值

//配置類,相當於applicationContext.xml
@Configuration
public class MyConfig {


    @Bean //id=方法名(myStudent)
    public Student myStudent(){
        Student student=new Student(2,"fg",34);
        return student;
    }
}

取bean: 

ApplicationContext context=new AnnotationConfigApplicationContext(MyConfig.class);
Student myStudent = (Student) context.getBean("myStudent");

注意:兩種形式獲取的IOC是獨立的  
註解形式向IOC容器存放bean詳解:
1.必須有@Configuration
2.形式:
2.1 三層組件(Controller、Service、Dao):             (1)將三層組件分別加註解@Controller、@Service、@Repository等價於@Commponent              (2)納入掃描器 a.xml配置

<context:component-scan base-package="org.ghl.controller"></context:component-scan>

b.註解形式      component-scan只對三層組件負責。    
給掃描器指定規則:                 過濾類型:FilterType(ANNOTATION, ASSIGNABLE_TYPE, CUSTOM)                 ANNOTATION:三層註解類型@Controller、@Service、@Repository等價於@Commponent

排除:
@ComponentScan(value = "org.ghl",excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION ,value = {Service.class,Repository.class})})
包含:(有默認行為,可以通過useDefaultFilters禁止)
@ComponentScan(value = "org.ghl",includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION ,value = {Service.class,Repository.class})},useDefaultFilters = false)

  ASSIGNABLE_TYPE:指具體的類。

@ComponentScan(value = "org.ghl",includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE ,value = {StudentController.class})},useDefaultFilters = false)

區分:ANNOTATION:Service.class指標有@Service的所有類;           ASSIGNABLE_TYPE:指具體的類。                 CUSTOM:自定義:自己定義規則

@ComponentScan(value = "org.ghl",includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM ,value = {MyFilter.class})},useDefaultFilters = false)

 

public class MyFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //拿到掃描器value = "org.ghl"包中的所有標有三層組件註解類的名字
        String className = classMetadata.getClassName();
        //只過濾出和student相關的三層組件
        if (className.contains("Student")){
            return true;  //表示包含
        }
        return false; //表示排除
    }
}

  

2.2 非三層組件(Student.clss/轉換器等): (1)@Bean+方法的返回值,id的默認值為方法名,也可以通過@Bean(“stu”)修改。 (2)import/FactoryBean  
bean的作用域

(@Scope(“singleton”))scope=”singleton”:單例 scope=”prototype”:原型、多實例。
執行的時機(產生bean的時機):         singleton:容器在初始化時,就創建對象,且只創建一次; 也支持延遲加載:在第一次使用時,創建對象。在config中加入@Lazy。         prototype:容器在初始化時,不創建對象,在每次使用時(每次從容器獲取對象時),再創建對象。         
條件註解 可以讓某一個Bean在某些條件下加入IOC容器。 (1)準備bean; (2)增加條件bean:給每個bean設置條件,必須實現Condition接口。 (3)根據條件加入IOC容器
  回顧給IOC加入Bean的方法:        註解:全部在@Configuration配置中設置:                 三層組件:掃描器+三層註解                 非三層組件:(1)@Bean+返回值                                      (2)@import                                      (3)FactoryBean(工廠Bean)
 
@import使用:         (1)直接編寫到@Import中; @Import({Apple.class,Banana.class})         (2)自定義ImportSelector接口的實現類,通過selectimports方法實現(方法的返回值就是要納入IOC容器的Bean)。並告知程序自己編寫的實現類。

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"org.ghl.entity.Apple","org.ghl.entity.Banana"}; //方法的返回值就是要納入IOC容器的Bean
    }
}
@Import({MyImportSelector.class})

    (3)編寫ImporBeanDefinitionRegistrar接口的實現類並重寫方法。 

public class MyImporBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        //BeanDefinition beanDefinition=new RootBeanDefinition(Orange.class);
        BeanDefinition beanDefinition=new RootBeanDefinition("org.ghl.entity.Orange");
        beanDefinitionRegistry.registerBeanDefinition("myorange",beanDefinition);


    }
}  
@Import({MyImporBeanDefinitionRegistrar.class})

  

FactoryBean(工廠Bean)         1.寫實現類和重寫方法;  

public class MyFactoryBean implements FactoryBean{
    @Override
    public Object getObject() throws Exception {
        return new Apple();
    }

    @Override
    public Class<?> getObjectType() {
        return Apple.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

  2.註冊到@Bean中  

@Bean
public FactoryBean<Apple>  myFactoryBean(){
    return new MyFactoryBean();
}

注意:需要通過&區分獲取的對象是哪一個。不加&,獲取的是最內部真實的apple,如果加&,獲取的是FactoryBean。  

  

  

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

※教你寫出一流的銷售文案?

「敢檢討核電海嘯對策就開除你喔!」 解析處處矛盾的福島核災判決

文:宋瑞文(媽媽監督核電廠聯盟特約撰述)

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

象牙海岸法令鬆綁 開放可可業剷平雨林

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

※教你寫出一流的銷售文案?

Jmeter系列(32)- 詳解 CSV 數據文件設置

如果你想從頭學習Jmeter,可以看看這個系列的文章哦

https://www.cnblogs.com/poloyy/category/1746599.html

 

了解一哈什麼是 CSV 文件

  • 為了實現簡單的數據存儲,是一個純文本的文件
  • 最通用的一種文件格式,它可以非常容易地被導入各種PC表格及數據庫中
  • CSV 文件可以用記事本、excel打開;用記事本打開的話,每一列數據都用逗號隔開

 

為什麼要用 CSV 數據文件?

  • 從外部導入測試數據,相當於數據參數化
  • 通過從文件中導入大量的測試數據,來模擬大量真實用戶發送併發請求

 

CSV 數據文件設置

 

CSV 數據文件設置界面介紹

 

字段含義

字段 含義
Filename 文件名
File encoding 文件編碼
Variable Names
  • 變量名稱
  • 多個變量用 , 分隔
Ignore first line
  • 忽略首行
  • 只在設置了變量名稱后才生效
Delimiter
  • 分隔符
  • 默認 , 
Allow quoted data? 是否允許帶引號
Recycle on EOF? 遇到文件結束符EOF 后再次循環
Stop thread on EOF? 遇到文件結束符EOF 后停止運行線程?
Sharing mode 線程共享模式

後續通過各種栗子來深入理解常用字段的含義

 

單個字段的栗子

csv 測試數據

這裏用記事本方式當 CSV 數據文件,共有 10 條記錄

 

線程組結構樹

${num} 是計數器裏面聲明的變量,從 1 開始遞增到 15

 

線程組屬性

線程數和數據量一致,都是 15

 

csv 數據文件設置

 

運行結果

 

知識點

  • 忽略首行 True:一般首行都是字段名字,比如栗子的 mobile,一般都需要忽略除非沒有字段名
  • 是否允許帶引號 False:可以看到有引號的三條記錄 8、9、10,都還是保留了引號
  • 再次循環 True:csv 文件共有 10 條記錄,但線程數有 15 個,循環 10 次后,重頭開始循環;可以看到 11-15的手機號和1-5的手機號
  • 停止線程 False:取了 10 次值之後就到了文件尾部,但並不會停止運行線程,後面會舉個反例

 

多個字段的綜合栗子

csv 測試數據

兩個字段,共有 10 條記錄,最後三條記錄有分別有三種引號

 

csv 數據文件設置

線程組結構樹和上面栗子差不多一樣,線程數仍然 = 15

和第一個例子的配置項相反:不忽略首行,允許帶引號,遇到文件結束符不再循環

 

運行結果

  • 不忽略首行就會把首行的字段名都返回回來,如:1-mobile-age
  • 數據有雙引號 “” 時,會把雙引號忽略掉,  單引號不算
  • EOF 是文件結束符,沒有開啟再次循環時,會直接返回 EOF

 

開啟遇到文件結束符停止線程

還是上個栗子的線程組,只是改了下配置項

 

運行結果

可以看到,線程數 = 15,但只有 10 條數據,當跑了 10 個線程后,沒有數據了,所以停止運行

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

Java 多線程基礎(十二)生產者與消費者

 Java 多線程基礎(十二)生產者與消費者

一、生產者與消費者模型

生產者與消費者問題是個非常典型的多線程問題,涉及到的對象包括“生產者”、“消費者”、“倉庫”和“產品”。他們之間的關係如下:

①、生產者僅僅在倉儲未滿時候生產,倉滿則停止生產。
②、消費者僅僅在倉儲有產品時候才能消費,倉空則等待。
③、當消費者發現倉儲沒產品可消費時候會通知生產者生產。
④、生產者在生產出可消費產品時候,應該通知等待的消費者去消費。

生產者消費者模型具體來講,就是在一個系統中,存在生產者和消費者兩種角色,他們通過內存緩衝區進行通信,生產者生產消費者需要的資料,消費者把資料做成產品。生產消費者模式如下圖。

在日益發展的服務類型中,譬如註冊用戶這種服務,它可能解耦成好幾種獨立的服務(賬號驗證,郵箱驗證碼,手機短信碼等)。它們作為消費者,等待用戶輸入數據,在前台數據提交之後會經過分解併發送到各個服務所在的url,分發的那個角色就相當於生產者。消費者在獲取數據時候有可能一次不能處理完,那麼它們各自有一個請求隊列,那就是內存緩衝區了。做這項工作的框架叫做消息隊列。

二、生產者與消費者實現

下面通過生產包子的例子及wait()/notify()方式實現該模型(後面學習線程池相關內容之後,再通過其它方式實現生產/者消費者模型)。

麵包類:

public class Bread {
    private int capacity;    // 麵包的容量
    private int size;        // 麵包的實際數量
    public Bread(int capacity) {
        this.capacity = capacity;
        this.size = 0;
    }
    
    // 生產麵包
    public synchronized void produce(int val) {
        try {
             // left 表示“想要生產的數量”(有可能生產量太多,需多此生產)
            int left = val;
            while (left > 0) {
                // 庫存已滿時,等待“消費者”消費產品。
                while (size >= capacity)
                    wait();
                // 獲取“實際生產的數量”(即庫存中新增的數量)
                // 如果“庫存”+“想要生產的數量”>“總的容量”,則“實際增量”=“總的容量”-“當前容量”。(此時填滿倉庫)
                // 否則“實際增量”=“想要生產的數量”
                int inc = (size+left)>capacity ? (capacity-size) : left;
                size += inc;
                left -= inc;
                System.out.printf("%s produce(%3d) --> left=%3d, inc=%3d, size=%3d\n",
                        Thread.currentThread().getName(), val, left, inc, size);
                // 通知“消費者”可以消費了。
                notifyAll();
            }
        }catch(InterruptedException e) {
            e.printStackTrace();
        }
    }
    // 消費麵包
    public synchronized void consume(int val) {
        try {
             // left 表示“客戶要消費數量”(有可能消費量太大,庫存不夠,需多此消費)
            int left = val;
            while (left > 0) {
                // 庫存為0時,等待“生產者”生產產品。
                while (size <= 0)
                    wait();
                // 獲取“實際消費的數量”(即庫存中實際減少的數量)
                // 如果“庫存”<“客戶要消費的數量”,則“實際消費量”=“庫存”;
                // 否則,“實際消費量”=“客戶要消費的數量”。
                int dec = (size<left) ? size : left;
                size -= dec;
                left -= dec;
                System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d\n",
                        Thread.currentThread().getName(), val, left, dec, size);
                notifyAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

生產者類

public class Producer{
    Bread bread;
    public Producer(Bread bread) {
        this.bread = bread;
    }
    public void produce(final int val) {
        new Thread(() -> {
            bread.produce(val);
        }).start();;
    }
}

消費者類

public class Customer {
    private Bread bread;
    public Customer(Bread bread) {
        this.bread = bread;
    }
    public void consume(final int val) {
        new Thread(() -> {
            bread.consume(val);
        }).start();;
    }
}

測試類代碼

public class Demo {
    public static void main(String[] args) {
        Bread bread = new Bread(100);
        Producer producer = new Producer(bread);
        Cunstomer customer = new Customer(bread);
        
        producer.produce(60);
        producer.produce(120);
        consumer.consume(90);
        consumer.consume(150);
        producer.produce(110);
    }
}
// 運行結果
Thread-1 produce( 60) --> left=  0, inc= 60, size= 60
Thread-5 produce(110) --> left= 70, inc= 40, size=100
Thread-4 consume(150) <-- left= 50, dec=100, size=  0
Thread-2 produce(120) --> left= 20, inc=100, size=100
Thread-3 consume( 90) <-- left=  0, dec= 90, size= 10
Thread-4 consume(150) <-- left= 40, dec= 10, size=  0
Thread-5 produce(110) --> left=  0, inc= 70, size= 70
Thread-4 consume(150) <-- left=  0, dec= 40, size= 30
Thread-2 produce(120) --> left=  0, inc= 20, size= 50

說明:

①、Producer是“生產者”類,它與“麵包(bread)”關聯。當調用“生產者”的produce()方法時,它會新建一個線程並向“麵包類”中生產產品。
②、Customer是“消費者”類,它與“麵包(bread)”關聯。當調用“消費者”的consume()方法時,它會新建一個線程並消費“麵包類”中的產品。
③、Bread是麵包類,記錄“麵包的產量(capacity)”以及麵包當前實際數目(size)”。
        麵包類的生產方法produce()和消費方法consume()方法都是synchronized方法,進入synchronized方法體,意味着這個線程獲取到了該“麵包”對象的同步鎖。這也就是說,同一時間,生產者和消費者線程只能有一個能運行。通過同步鎖,實現了對“殘酷”的互斥訪問。
       對於生產方法 produce() 而言:當麵包量滿時,生產者線程等待,需要等待消費者消費產品之後,生產線程才能生產;生產者線程生產完麵包之後,會通過 notifyAll() 喚醒同步鎖上的所有線程,包括“消費者線程”,即我們所說的“通知消費者進行消費”。
      對於消費方法consume()而言:當倉庫為空時,消費者線程等待,需要等待生產者生產產品之後,消費者線程才能消費;消費者線程消費完產品之後,會通過 notifyAll() 喚醒同步鎖上的所有線程,包括“生產者線程”,即我們所說的“通知生產者進行生產”。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

※教你寫出一流的銷售文案?

特斯拉與 BMW 談合作 可望發展碳纖維與電池技術

特斯拉(Tesla)明星執行長 Elon Musk 爆料,德國豪華車品牌 BMW 與特斯拉曾洽商合作,範圍涵蓋電池與輕量化車體零件。   Musk 在接受德國媒體 Der Spiegel 專訪時表示,對 BMW 以碳纖維材料強化車體感到非常有興趣,認為相當具成本效益,雙方在非正式場合會面時,有討論過合作的可能,但尚未達成決議。   據路透社報導,BMW 為發展碳纖維原料而成立合資公司 SGL,i3 電動車與 i8 油電混合動力跑車的駕駛艙與後蓋零件均採用到碳纖維材料。除此之外,Musk 還透露有意與 BMW 一起搞電池科技,以及電動車充電站,他甚至於計畫 5~6 年內在德國蓋一座電池廠。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

新北清潔公司,居家、辦公、裝潢細清專業服務

※教你寫出一流的銷售文案?

【JAVA8新的時間與日期 API】- 傳統時間格式化的線程安全問題

Java8之前的日期和時間API,存在一些問題,最重要的就是線程安全的問題。這些問題都在Java8中的日期和時間API中得到了解決,而且Java8中的日期和時間API更加強大。

傳統時間格式化的線程安全問題

示例:

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

public class TestOldSimpleDateFormat {
    public static void main(String[] args) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Callable<Date> task = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
                return sdf.parse("2020-01-01");
            }
        };
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<Date>> list = new ArrayList<>();
        for (int i=0;i<10;i++){
            Future<Date> future = pool.submit(task);
            list.add(future);
        }
        for (Future<Date> future : list){
            System.out.println(future.get());
        }

     pool.shutdown(); } }

以上代碼運行會報錯:

 

 

報錯緣由:取部分源碼解釋

    /**
     * SimpleDateFormat 類的 parse 方法 部分源碼
     */
    public Date parse(String source) throws ParseException
    {
        ParsePosition pos = new ParsePosition(0);
        Date result = parse(source, pos); 
        if (pos.index == 0)
            throw new ParseException("Unparseable date: \"" + source + "\"" ,
                pos.errorIndex);
        return result;
    }

public Date parse(String text, ParsePosition pos)
    {
        // 省略上面諸多代碼
        Date parsedDate;

        CalendarBuilder calb = new CalendarBuilder();
        try {
            //這裏這個 calendar 對象是 SimpleDateFormat 類的父類 DateFormat 中的屬性  : protected Calendar calendar;
            parsedDate = calb.establish(calendar).getTime();//這個 calb.establish(calendar) 方法中,這個方法中的主要步驟不是原子操作,並且會對 calendar 對象進行修改,所以在多線程環境下就會出現線程安全問題。
            // 省略下面面諸多代碼
        }
        catch (IllegalArgumentException e) {
            //省略.........................
            return null;
        }
        return parsedDate;
    }
 Calendar establish(Calendar cal) {
        boolean weekDate = isSet(WEEK_YEAR)
                            && field[WEEK_YEAR] > field[YEAR];
        if (weekDate && !cal.isWeekDateSupported()) {
            // Use YEAR instead
            if (!isSet(YEAR)) {
                set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
            }
            weekDate = false;
        }

        cal.clear();
        // Set the fields from the min stamp to the max stamp so that
        // the field resolution works in the Calendar.
        for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
            for (int index = 0; index <= maxFieldIndex; index++) {
                if (field[index] == stamp) {
                    cal.set(index, field[MAX_FIELD + index]);
                    break;
                }
            }
        }

        if (weekDate) {
            int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
            int dayOfWeek = isSet(DAY_OF_WEEK) ?
                                field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
            if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
                if (dayOfWeek >= 8) {
                    dayOfWeek--;
                    weekOfYear += dayOfWeek / 7;
                    dayOfWeek = (dayOfWeek % 7) + 1;
                } else {
                    while (dayOfWeek <= 0) {
                        dayOfWeek += 7;
                        weekOfYear--;
                    }
                }
                dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
            }
            cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
        }
        return cal;
    }

綜上,我們可以看到 SimpleDateFormat 類中的parse 方法,調用了 CalendarBuilder 的 establish(calendar) 方法,並在方法中,對 calendar 對象進行了各種判斷及修改,並且這些操作都不是原子操作或同步操作,而這個calendar 對象又是 SimpleDateFormat 的父類 DateFormat 的一個實例變量,所以,在多線程同時調用SimpleDateFormat 的 parse 方法的時候,就會出現線程安全問題。


針對以上異常,JAVA8之前的解決辦法:

1. 將 SimpleDateFormat 對象定義成局部變量。

2. 加鎖。

3. 使用ThreadLocal,每個線程都擁有自己的SimpleDateFormat對象副本。

示例(加鎖):

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Callable<Date> task = new Callable<Date>() {
            @Override
            public synchronized Date call() throws Exception {//加個同步,解決問題
                return sdf.parse("2020-01-01");
//                return DateFormatThreadLocal.convert("2020-01-01");
            }
        };
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<Date>> list = new ArrayList<>();
        for (int i=0;i<10;i++){
            Future<Date> future = pool.submit(task);
            list.add(future);
        }
        for (Future<Date> future : list){
            System.out.println(future.get());
        }
        pool.shutdown();

 

示例(ThreadLocal):

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateFormatThreadLocal {
    private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd");
        }
    };
    public static Date convert(String source) throws Exception {
        return df.get().parse(source);
    }
}


////////////////////////////////////////////////////////////////

public class TestOldSimpleDateFormat {
    public static void main(String[] args) throws Exception {
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Callable<Date> task = new Callable<Date>() {
            @Override
            public Date call() throws Exception {
//                return sdf.parse("2020-01-01");
                return DateFormatThreadLocal.convert("2020-01-01");
            }
        };
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<Date>> list = new ArrayList<>();
        for (int i=0;i<10;i++){
            Future<Date> future = pool.submit(task);
            list.add(future);
        }
        for (Future<Date> future : list){
            System.out.println(future.get());
        }
     pool.shutdown();
} }

 

JAVA8的解決辦法:使用新的API(DateTimeFormatter  和 LocalDate )

示例:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class TestOldSimpleDateFormat {
    public static void main(String[] args) throws Exception {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        Callable<LocalDate> task = new Callable<LocalDate>() {
            @Override
            public LocalDate call() throws Exception {
//                return sdf.parse("2020-01-01");
                return LocalDate.parse("2020-01-01",formatter);
            }
        };
        ExecutorService pool = Executors.newFixedThreadPool(10);
        List<Future<LocalDate>> list = new ArrayList<>();
        for (int i=0;i<10;i++){
            Future<LocalDate> future = pool.submit(task);
            list.add(future);
        }
        for (Future<LocalDate> future : list){
            System.out.println(future.get());
        }
        pool.shutdown();
    }
}

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準