摘要:引起線程之間執行順序的是競爭條件。只有資源共享才會有線程安全的問題線程資源同步和線程之間的同步。對于方法或者代碼塊,當出現異常時,會自動釋放當前線程占用的鎖,因此不會由于異常導致出現死鎖現象。執行器執行器是實現的線程池。
package com.test; public class MyThread extends Thread{ @Override public void run() { System.out.println("新的線程開始運行"); } public static void main(String[] args) { System.out.println("main的主線程"); new MyThread().start(); //start方法調用以后,那么此時CPU有可能先執行新的線程。也有可能繼續執行原來的線程(執行后續的代碼) System.out.println("main的主線程"); } }
public class MyThread extends Thread{ @Override public void run() { System.out.println("新的線程開始運行"); } public static void main(String[] args) { System.out.println("main的主線程"); Thread t= new MyThread(); System.out.println(t.getState()); t.start(); System.out.println(t.getState()); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(t.getState()); t.start(); //只有線程狀態是NEW才可以調用start方法。 } }
引起線程之間執行順序的是競爭條件。
package com.spring; public class MyThread extends Thread{ public int count=0; @Override public void run() { count++; } public void countAdd(){ this.count++; } public static void main(String[] args) { System.out.println("main的主線程"); MyThread t= new MyThread(); t.setPriority(MAX_PRIORITY); t.start(); t.countAdd(); System.out.println(t.count); System.out.println(t.count); System.out.println(t.count); System.out.println(t.count); System.out.println(t.count); } }
并非只有靜態變量才會有線程不安全,如上,如果count++不是原子操作的話,成員變量依然會不安全。因為資源是共享的,而run方法卻在不同的線程中運行。
線程在真正執行的時候完全不是按照一條語句一條語句的執行。
比如:
if(count>0)
只要資源不共享,斷續著的切換執行根本沒有問題。只有資源共享才會有線程安全的問題
線程資源同步和線程之間的同步。
線程之間的同步就是比如A執行完之后要執行B,然后執行C。就是在線程之間有順序的執行。
等待與阻塞:
等待是等待另外一個線程出現結果,或者另一個線程的調度,阻塞是沒有獲得鎖
守護線程:
與守護進程是有區別的。當沒有工作線程的時候,就停止了。
wait方法等待并釋放這個鎖。
對于synchronized方法或者synchronized代碼塊,當出現異常時,JVM會自動釋放當前線程占用的鎖,因此不會由于異常導致出現死鎖現象。
有時候你會看到有所謂的類鎖和對象鎖的說法。
`假設我有一個類ClassA,其中有一個方法synchronized methodA(),那么當這個方法被調用的時候你獲得就是對象鎖,但是要注意,如果這個類有兩個實例,比如:
ClassA a = new ClassA();
ClassA b = new ClassA();
那么如果你在a這對象上調用了methodA,不會影響b這個對象,也就是說對于b這個對象,他也可以調用methodA,因為這是兩對象,所以說對象鎖是針對對象的。`
在這里主要討論一個使用上的問題,當我們使用sychronized鎖住某個對象時,我們鎖住的是這個引用本身,還是內存(堆)中的這個對象本身。對這個問題的一個延伸是,當我們在sychronized作用區域內,為這個引用附一個新值的時候,sychronized是否還有效?
先給出結論,sychronized鎖住的是內存(堆)中的對象,當引用被附上新值的時候,則相當于舊對象的鎖被釋放。這里不做理論討論,只是用程序進行驗證。
http://www.cnblogs.com/shipengzhi/articles/2223100.html
static synchronized 鎖住的是整個類。會影響到所有的實例。
執行器是Java實現的線程池。
package com.ex; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; public class Server { private ThreadPoolExecutor executor; public ThreadPoolExecutor getExecutor(){ return this.executor; } public Server(){ // executor=(ThreadPoolExecutor) Executors.newCachedThreadPool();// cache線程池在真正有任務的時候才初始化,隨著任務變化而變化 executor=(ThreadPoolExecutor) Executors.newFixedThreadPool(10);//固定任務的線程池 System.out.println("總共線程池------------------------"+executor.getPoolSize()); System.out.println("活動的線程池數量---------------------"+executor.getActiveCount()); } public void excuteTask(Task task){ executor.execute(task); System.out.println("一共得線程池"+executor.getPoolSize()); System.out.println("活動的線程池數量,即正在處理任務的線程數量"+executor.getActiveCount()); } public static void main(String[] args) { Server server=new Server(); for(int i=0;i<100;i++){ Task task=new Task("線程id"+i); server.excuteTask(task); } //主線程不斷詢問線程組是否執行完畢 while(true){ if(server.getExecutor().getCompletedTaskCount()==100){ System.out.println("總共線程池------------------------"+server.getExecutor().getPoolSize()); System.out.println("活動的線程池數量---------------------"+server.getExecutor().getActiveCount()); server.getExecutor().shutdown(); break; } } } } package com.ex; import java.util.Date; public class Task implements Runnable{ private String name; private Date date; public Task(String name){ this.date=new Date(); this.name=name; } @Override public void run() { try { System.out.println(this.name+"----開始執行任務"); Thread.sleep((long) (Math.random()*1000)); System.out.println(this.name+"----結束執行任務"); } catch (InterruptedException e) { e.printStackTrace(); } } }線程的內存模型
對于公共變量或者資源,線程會復制一份到屬于自己的線程棧,操作以后再放回公共資。在復制的過程中間,如果有其他線程修改了資源,那么復制的就不是最新的。這就是所謂的內存可見性問題。同步了當然不會存在這樣的問題,因為同一個時刻,另外一個線程必讀等待另一個線程讀寫完畢。
/** *=============================================================== * @CopyRight: 北京逸生活技術服務有限公司技術部 * @author: xujianxing * @date: 2016年3月16日 * @version: 1.0.0 *=============================================================== * 修訂日期 修訂人 描述 */ package syncdemo; import java.util.ArrayList; import java.util.HashSet; import java.util.List; /** *TODO *
TODO * @author xujinaxing * @date 2016年3月16日 * @see * @since * @modified TODO */ public class ThreadUnSafe extends Thread{ public static int flag=0; public static List
list=new ArrayList (); @Override public void run() { // TODO Auto-generated method stub super.run(); flag++; //添加的時候必須同步。也就是說保證list是內存可見的。 synchronized (list) { list.add(flag); } System.out.println(flag); } public static void main(String[] args) { for(int i=0;i<10000;i++){ new ThreadUnSafe().start(); } try { Thread.currentThread().sleep(15000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } int size=new HashSet (ThreadUnSafe.list).size(); System.out.println("size"+size); } }
打印的值是9991.說明了線程之間由于存取不及時。導致set的size小于1000.
/** *=============================================================== * @CopyRight: 北京逸生活技術服務有限公司技術部 * @author: xujianxing * @date: 2016年3月16日 * @version: 1.0.0 *=============================================================== * 修訂日期 修訂人 描述 */ package syncdemo; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** *TODO *
TODO * @author xujinaxing * @date 2016年3月16日 * @see * @since * @modified TODO */ public class ThreadSafe extends Thread{ public static AtomicInteger flag=new AtomicInteger(0); public static List
list=new ArrayList (); @Override public void run() { // TODO Auto-generated method stub super.run(); int i=flag.incrementAndGet(); synchronized (list) { list.add(i); } System.out.println(flag.get()); } public static void main(String[] args) { for(int i=0;i<20000;i++){ new ThreadSafe().start(); } try { Thread.currentThread().sleep(15000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } int size=new HashSet (ThreadSafe.list).size(); System.out.println("size"+size); } }
上面的這個代碼是線程安全的。性能高,是李利用硬件提供的原子操作。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/64343.html
摘要:最近聽很多面試的小伙伴說,網上往往是一篇一篇的多線程的文章,除了書籍沒有什么學習多線程的一系列文章。將此線程標記為線程或用戶線程。 最近聽很多面試的小伙伴說,網上往往是一篇一篇的Java多線程的文章,除了書籍沒有什么學習多線程的一系列文章。但是僅僅憑借一兩篇文章很難對多線程有系統的學習,而且面試的時候多線程這方面的知識往往也是考察的重點,所以考慮之下決定寫一系列關于Java多線程的文章...
摘要:但是并不是什么多線程就可以隨便用,有的時候多線程反而會造成系統的負擔,而且多線程還會造成其他的數據問題,下面就來介紹一下多線程面臨的問題。下面這張圖是多線程運行時候的情況,我們發現上下文切換的次數暴增。 并發的概念: 在Java中是支持多線程的,多線程在有的時候可以大提高程序的速度,比如你的程序中有兩個完全不同的功能操作,你可以讓兩個不同的線程去各自執行這兩個操作,互不影響,不需要執行...
摘要:如圖所示,帶有的所有線程構造方法都可以定義線程組的。線程組還能統一設置組內所有線程的最高優先級,線程單獨設置的優先級不會高于線程組設置的最大優先級。 前面的文章,棧長和大家分享過多線程創建的3種方式《實現 Java 多線程的 3 種方式》。 但如果線程很多的情況下,你知道如何對它們進行分組嗎? 和 Dubbo 的服務分組一樣,Java 可以對相同性質的線程進行分組。 來看下線程類 Th...
摘要:線程可以被稱為輕量級進程。一個守護線程是在后臺執行并且不會阻止終止的線程。其他的線程狀態還有,和。上下文切換是多任務操作系統和多線程環境的基本特征。在的線程中并沒有可供任何對象使用的鎖和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻譯:并發編程網 - 鄭旭東 校對:方騰飛 多...
摘要:相比與其他操作系統包括其他類系統有很多的優點,其中有一項就是,其上下文切換和模式切換的時間消耗非常少。因為多線程競爭鎖時會引起上下文切換。減少線程的使用。很多編程語言中都有協程。所以如何避免死鎖的產生,在我們使用并發編程時至關重要。 系列文章傳送門: Java多線程學習(一)Java多線程入門 Java多線程學習(二)synchronized關鍵字(1) java多線程學習(二)syn...
摘要:多線程環境下的一些問題安全性問題在沒有正確同步的情況下,多線程環境下程序可能得出錯誤的結果。一些相關概念競爭條件多線程的環境下,程序執行的結果取決于線程交替執行的方式。而線程的交替操作順序是不可預測的,如此程序執行的結果也是不可預測的。 入口 Java多線程的應用復雜性之如jvm有限的幾個內存方面的操作和規范,就像無數紛繁復雜的應用邏輯建立在有限的指令集上。 如何寫出線程安全的程序,有...
閱讀 3931·2021-11-24 10:46
閱讀 1820·2021-11-16 11:44
閱讀 2297·2021-09-22 16:02
閱讀 1405·2019-08-30 15:55
閱讀 1134·2019-08-30 12:46
閱讀 570·2019-08-28 18:31
閱讀 2765·2019-08-26 18:38
閱讀 1100·2019-08-23 16:51