package com.lvzhi;
/** * Created by lvzhi on 2017/9/3 */ public class MyThread { private int num = 0; public synchronized void print(String args) throws InterruptedException { if (args.equals("a")) { System.out.println("I'am a "); num = 100; Thread.sleep(1000L); } else { System.out.println("I'am b "); num = 200; Thread.sleep(1000L); } System.out.println("Over"); } public static void main(String[] args) { MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { try { myThread1.print("a"); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { try { myThread2.print("b"); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread1.start(); thread2.start(); } }
該段代碼輸出的結果是thread1和thread2的亂序結果,由於synchronized是在非static方法,那麼對於線程來講就是myThread1和myThread2是相互獨立的,相似於上邊的代碼跟沒加synchronized效果是同樣的。結果以下: I'am a I'am b Over Overjava
*java類型中static方法mysql
package com.lvzhi;
/** * Created by lvzhi on 2017/9/3 */ public class MyThread { private static int num = 0; public static synchronized void print(String args) throws InterruptedException { if (args.equals("a")) { System.out.println("I'am a "); num = 100; Thread.sleep(1000L); } else { System.out.println("I'am b "); num = 200; Thread.sleep(1000L); } System.out.println("Over"); } public static void main(String[] args) { MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); Thread thread1 = new Thread(new Runnable() { @Override public void run() { try { myThread1.print("a"); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread thread2 = new Thread(new Runnable() { @Override public void run() { try { myThread2.print("b"); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread1.start(); thread2.start(); } }
該段代碼輸出的結果是thread1和thread2的有序結果,由於synchronized是在static方法上,static方法特性本身去百度,因此結果是有序的。結果以下: I'am a Over I'am b Oversql
1、sleep & wait編程
有時間讀讀源碼數組
這個配合callable使用,其實就是多線程有返回值,so easy !瀏覽器
Master-Worker是經常使用的並行計算模式。它的核心思想是系統由兩類進程協做工做:Master進程和Worker進程。Master負責接收和分配任務,Worker負責處理子任務。當各個Worker子進程處理完成後,會將結果返回給Master,由Master做概括總結。其好處就是能將一個大任務分解成若干個小任務,並行執行,從而提升系統的吞吐量。處理過程以下圖所示:服務器
Master-Worker模式是一種將串行任務並行化的方案,被分解的子任務在系統中能夠被並行處理,同時,若是有須要,Master進程不須要等待全部子任務都完成計算,就能夠根據已有的部分結果集計算最終結果集。session
Semaphore當前在多線程環境下被擴放使用,操做系統的信號量是個很重要的概念,在進程控制方面都有應用。Java 併發庫 的Semaphore 能夠很輕鬆完成信號量控制,Semaphore能夠控制某個資源可被同時訪問的個數,經過 acquire() 獲取一個許可,若是沒有就等待,而 release() 釋放一個許可。好比在Windows下能夠設置共享文件的最大客戶端訪問個數。 Semaphore實現的功能就相似廁全部5個坑,假若有10我的要上廁所,那麼同時只能有多少我的去上廁所呢?同時只能有5我的可以佔用,當5我的中 的任何一我的讓開後,其中等待的另外5我的中又有一我的能夠佔用了。另外等待的5我的中能夠是隨機得到優先機會,也能夠是按照先來後到的順序得到機會,這取決於構造Semaphore對象時傳入的參數選項。單個信號量的Semaphore對象能夠實現互斥鎖的功能,而且能夠是由一個線程得到了「鎖」,再由另外一個線程釋放「鎖」,這可應用於死鎖恢復的一些場合。 ps:有個重要問題,該段代碼在main方法中運行,能夠達到預期的效果,若是用junit的方法來測試,其預期的結果差很遠。數據結構
public class SemaphoreTest { public static void main(String[] args) { // 線程池 ExecutorService exec = Executors.newCachedThreadPool(); // 只能5個線程同時訪問 final Semaphore semp = new Semaphore(5); // 模擬20個客戶端訪問 for (int index = 0; index < 50; index++) { final int NO = index; Runnable run = new Runnable() { public void run() { try { // 獲取許可 semp.acquire(); System.out.println("Accessing: " + NO); Thread.sleep((long) (Math.random() * 10000)); // 訪問完後,釋放 semp.release(); //availablePermits()指的是當前信號燈庫中有多少個能夠被使用 System.out.println("-----------------" + semp.availablePermits()); } catch (InterruptedException e) { e.printStackTrace(); } } }; exec.execute(run); } // 退出線程池 exec.shutdown(); }
public class ConditionTest { private static Lock lock = new ReentrantLock(); private static final Condition firstCondition = lock.newCondition(); private static final Condition secondCondition = lock.newCondition(); //以上的兩個condition是不同的,不能用secondCondition去喚醒firstCondition public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { try { lock.lock(); System.out.println("wait"); firstCondition.await(); System.out.println("over"); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } }).start(); new Thread(new Runnable() { @Override public void run() { try { lock.lock(); System.out.println("enter"); Thread.sleep(10000); System.out.println("out"); firstCondition.signal(); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } }).start(); } }
公平鎖:公平鎖講究先來先到,線程在獲取鎖時,若是這個鎖的等待隊列中已經有線程在等待,那麼當前線程就會進入等待隊列中; 非公平鎖:無論是否有等待隊列,若是能夠獲取鎖,則馬上佔有鎖對象。 一、ReentrantLock 擁有Synchronized相同的併發性和內存語義,此外還多了 鎖投票,定時鎖等候和中斷鎖等候多線程
線程A和B都要獲取對象O的鎖定,假設A獲取了對象O鎖,B將等待A釋放對O的鎖定,
若是使用 synchronized ,若是A不釋放,B將一直等下去,不能被中斷
若是 使用ReentrantLock,若是A不釋放,可使B在等待了足夠長的時間之後,中斷等待,而幹別的事情
其實,這三個均可以用於多線程中,好久之前就用過,只不過又忘記了。 其實就是,能夠等待全部的線程都執行完,能夠彙總一下。再此,再記錄一下。
暫時不研究,目前全部的項目都沒用過,用過的框架中不知道用沒有用,因此,僅此先記錄一下,若是之後工做中用到,再仔細研究。
1,同步和異步是針對應用程序與內核的交互而言的。
2,阻塞和非阻塞是針對於進程在訪問數據的時候,根據IO操做的就緒狀態來採起的不一樣方式,說白了是一種讀取或者寫入操做函數的實現方式,阻塞方式下讀取或者寫入函數將一直等待,而非阻塞方式下,讀取或者寫入函數會當即返回一個狀態值。
由上描述基本能夠總結一句簡短的話,同步和異步是目的,阻塞和非阻塞是實現方式。
同步阻塞IO(JAVA BIO): 同步並阻塞,服務器實現模式爲一個鏈接一個線程,即客戶端有鏈接請求時服務器端就須要啓動一個線程進行處理,若是這個鏈接不作任何事情會形成沒必要要的線程開銷,固然能夠經過線程池機制改善。
同步非阻塞IO(Java NIO) : 同步非阻塞,服務器實現模式爲一個請求一個線程,即客戶端發送的鏈接請求都會註冊到多路複用器上,多路複用器輪詢到鏈接有I/O請求時才啓動一個線程進行處理。用戶進程也須要時不時的詢問IO操做是否就緒,這就要求用戶進程不停的去詢問。
異步阻塞IO(Java NIO):
此種方式下是指應用發起一個IO操做之後,不等待內核IO操做的完成,等內核完成IO操做之後會通知應用程序,這其實就是同步和異步最關鍵的區別,同步必須等待或者主動的去詢問IO是否完成,那麼爲何說是阻塞的呢?由於此時是經過select系統調用來完成的,而select函數自己的實現方式是阻塞的,而採用select函數有個好處就是它能夠同時監聽多個文件句柄(若是從UNP的角度看,select屬於同步操做。由於select以後,進程還須要讀寫數據),從而提升系統的併發性!
(Java AIO(NIO.2))異步非阻塞IO:
在此種模式下,用戶進程只須要發起一個IO操做而後當即返回,等IO操做真正的完成之後,應用程序會獲得IO操做完成的通知,此時用戶進程只須要對數據進行處理就行了,不須要進行實際的IO讀寫操做,由於真正的IO讀取或者寫入操做已經由內核完成了。
同步和異步是相對於應用和內核的交互方式而言的,同步 須要主動去詢問,而異步的時候內核在IO事件發生的時候通知應用程序,而阻塞和非阻塞僅僅是系統在調用系統調用的時候函數的實現方式而已。
目前理解起來有點沒有徹底搞明白,等之後再搞一次。
A = 0011 1100 B = 0000 1101
操做符 | 描述 | 例子 |
---|---|---|
若是相對應位都是1,則結果爲1,不然爲0 | & | (A&B),獲得12,即0000 1100 |
| | 若是相對應位都是0,則結果爲0,不然爲1 | (A | B)獲得61,即 0011 1101 |
^ | 若是相對應位值相同,則結果爲0,不然爲1 | (A ^ B)獲得49,即 0011 0001 |
〜 | 按位補運算符翻轉操做數的每一位,即0變成1,1變成0。 | (〜A)獲得-61,即1100 0011 |
<< | 按位左移運算符。左操做數按位左移右操做數指定的位數。 | A << 2獲得240,即 1111 0000 |
>> | 按位右移運算符。左操做數按位右移右操做數指定的位數。 | A >> 2獲得15即 1111 |
>>> | 按位右移補零操做符。左操做數的值按右操做數指定的位數右移,移動獲得的空位以零填充。 | A>>>2獲得15即0000 1111 |
> >* 負數的表示方法: 原碼:一個整數,按照絕對值大小轉換成的二進制數,稱爲原碼。 反碼:將二進制數按位取反,所得的新二進制數稱爲原二進制數的反碼。 補碼:反碼加1稱爲補碼。 ![此處輸入圖片的描述][2]
byte只有8位,若是byte中的數字爲負數,那麼在默認轉化位int的時候會發生錯誤,0XFF默認是整形,運算後,就至關於顯式的轉換爲int,不會出現二進制上的錯誤。
⑴一個數爲正,則它的原碼、反碼、補碼相同 ⑵一個數爲負,剛符號位爲1,其他各位是對原碼取反,而後整個數加1
-1的原碼爲 10000001 -1的反碼爲 11111110
-1的補碼爲 11111111
0的原碼爲 00000000 0的反碼爲 11111111(正零和負零的反碼相同)
0的補碼爲 100000000(舍掉打頭的1,正零和負零的補碼相同)
Integer.toHexString的參數是int,若是不進行&0xff,那麼當一個byte會轉換成int時,因爲int是32位,而byte只有8位這時會進行補位, 例如補碼11111111的十進制數爲-1轉換爲int時變爲11111111111111111111111111111111好多1啊,呵呵!即0xffffffff可是這個數是不對的,這種補位就會形成偏差。 和0xff相與後,高24比特就會被清0了,結果就對了。 Java中的一個byte,其範圍是-128~127的,而Integer.toHexString的參數原本是int,若是不進行&0xff,那麼當一個byte會轉換成int時,對於負數,會作位擴展,舉例來講,一個byte的-1(即0xff),會被轉換成int的-1(即0xffffffff),那麼轉化出的結果就不是咱們想要的了。 而0xff默認是整形,因此,一個byte跟0xff相與會先將那個byte轉化成整形運算,這樣,結果中的高的24個比特就總會被清0,因而結果老是咱們想要的
shadow clone(淺克隆):
parallel collector(throughput collector) 並行收集器:使用多線程的方式,利用多CUP來提升GC的效率,主要以到達必定的吞吐量爲目標。 concurrent collector(concurrent low pause collector) 併發收集器:使用多線程的方式,利用多CUP來提升GC的效率,併發完成大部分工做,使得gc pause短。
以上二者主要區別:throughput collector只在young area使用使用多線程,而concurrent low pause collector則在tenured generation也使用多線程
java交流羣669823128