Java 線程寶典
此文 為垃圾文 本人復習用的 emmm
- 多線程:指的是這個程序(一個進程)運行時產生了不止一個線程
- 並行與並發:
- 並行:多個cpu實例或者多臺機器同時執行一段處理邏輯,是真正的同時。
- 並發:通過cpu調度算法,讓用戶看上去同時執行,實際上從cpu操作層面不是真正的同時。並發往往在場景中有公用的資源,那麽針對這個公用的資源往往產生瓶頸,我們會用TPS或者QPS來反應這個系統的處理能力。
進程和線程的區分
第一種實現方式:通過繼承Thread類來實現的 線程
摘要:
code:
package com.java.Thread; public class MyThread {public static void main(String[] args){ Apple a1 = new Apple("壞蛋"); a1.start(); Apple a2 = new Apple("好人"); a2.start(); } } class Apple extends Thread{ private String name; public Apple(String name){ this.name = name; } public voidrun(){ for (int i = 1; i < 10; i++){ System.out.println(name+""+i); } } }
每一個線程從的它的創建到銷毀都有一個狀態 如下是線程的各種狀態:
線程的四種狀態
然後實現現成的 第二種方式 實現 Runnable接口
code如下:
package cn.java.thread; public class RunnableDemo { public static void main(String[] args) { Test t1= new Test("haoren"); Test t2 = new Test("hairen"); Thread th1 = new Thread(t1); Thread th2 = new Thread(t2); th1.start(); th2.start(); } } class Test implements Runnable{ private String name; public Test(String name){ this.name = name; } public void run(){ for(int i=0;i<10;i++){ System.out.println(name+":"+i); } } }
Thread和Runnable的關系
1.Thread是Ruuable的之類
2.實際上Thread和Runable的關系 跟代理設計模式很像, 這裏的Thread就是代理類。我們自己所實現的類才是real。
Thread和Runnable的區別
Runable可以共享數據
code如下:
package cn.java.thread; public class ShareDemo { public static void main(String[] args) { Tickets t1 = new Tickets(); Thread th1 = new Thread(t1); Thread th2 = new Thread(t1); th1.start(); th2.start(); } } class Tickets implements Runnable{ private int ticket = 5; public void run(){ for(int i=0;i<5;i++){ if(ticket>0) System.out.print(ticket--); } } }
然後 我說說這裏面的 一個叫做jojn()的東東 網上各種帖子眾說紛紜 而對他的理解就是 4個字 強制執行 做一個簡單的驗證吧.
package com.java.Thread; public class MyJoin { public static void main(String[] ARGS){ MyThread2 mt1 = new MyThread2(); mt1.setName("線程1"); mt1.start(); for (int i = 0; i < 10; i++) { if(i==5){ try { mt1.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(i); } } } class MyThread2 extends Thread { /*public MyThread(String string) { }*/ public void run() { int i = 0; while (i < 10) { System.out.println(Thread.currentThread().getName()); i++; } } }
運行結果如下
然後在 說說 interrupt 中斷 一個線程意味著在該線程完成任務之前停止其正在進行的一切,有效地中止其當前的操作。線程是死亡、還是等待新的任務或是繼續運行至下一步,就取決於這個程序。雖然初次看來它可能顯得簡單,但是,你必須進行一些預警以實現期望的結果。你最好還是牢記以下的幾點告誡。
首先,忘掉Thread.stop方法。雖然它確實停止了一個正在運行的線程,然而,這種方法是不安全也是不受提倡的,這意味著,在未來的Java版本中,它將不復存在。
一些輕率的家夥可能被另一種方法Thread.interrupt所迷惑。盡管,其名稱似乎在暗示著什麽,然而,這種方法並不會中斷一個正在運行的線程(待會將進一步說明),正如Listing A中描述的那樣。它創建了一個線程,並且試圖使用Thread.interrupt方法停止該線程。Thread.sleep()方法的調用,為線程的初始化和中止提供了充裕的時間。線程本身並不參與任何有用的操作。
code如下:
package com.java.Thread; public class MyInterrupt { public static void main(String[] args) { // TODO Auto-generated method stub MyThread3 mt = new MyThread3(); mt.start(); try { Thread.sleep(2000); System.out.println("main休眠結束"); } catch (InterruptedException e) { e.printStackTrace(); } mt.interrupt(); } } class MyThread3 extends Thread{ public void run(){ System.out.println("進入run"); try { Thread.sleep(8000); } catch (InterruptedException e) { // TODO Auto-generated catch block //e.printStackTrace(); System.out.println("run休眠結束!!!");//sleep被中斷會拋出InterruptedException 推薦直接拋出 不要捕獲 } System.out.println("run運行結束"); } }
然後來到線程禮讓 俗話點說 就是 線程A是個君子 看見線程B是個 美女就幹什麽都讓著她 讓她先過..
code如下:
package com.java.Thread; //線程禮讓 public class MyYield { public static void main(String[] ARGS){ MyThred m1 = new MyThred(); Thread t1 = new Thread(m1,"李四"); Thread t2 = new Thread(m1,"王五"); t1.start(); t2.start(); } } class MyThred implements Runnable{ @Override public void run() { for (int i = 0; i < 5; i++){ System.out.println(Thread.currentThread().getName()+"運行>>>>>" + i); if (i==2) { System.out.println("線程禮讓"); Thread.currentThread().yield(); } } } }
然後 來到 setdaenmo 後臺線程設置
Java中線程分為兩種類型:用戶線程和守護線程。通過Thread.setDaemon(false)設置為用戶線程;通過Thread.setDaemon(true)設置為守護線程。如果不設置次屬性,默認為用戶線程。
用戶線程和守護線程的區別:
1. 主線程結束後用戶線程還會繼續運行,JVM存活;主線程結束後守護線程和JVM的狀態又下面第2條確定。
2.如果沒有用戶線程,都是守護線程,那麽JVM結束(隨之而來的是所有的一切煙消雲散,包括所有的守護線程)。
code如下:
package com.java.Thread; public class SetDaemon { public static void main(String[] ARGS){ Persons p1 = new Persons(); Thread th = new Thread(p1); th.setDaemon(true);//如果不加此語句就永遠無法結束 th.start(); } } class Persons implements Runnable{ @Override public void run() { while (true){ System.out.println("哈哈哈哈哈哈sss"); } } }
然後 設置線程的優先級別 這點要說說 高的不一定會優先執行.
這是定義表
通過 setPriority方法來執行
來到重點中的重點 拿個小本本記住 線程安全
導致線程安全出現的原因:
所以 我們為了解決這個問題 推出了 同步 synchronized
然後同步又有兩種模式 一種是同步代碼塊 另外一種是同步函數 這兩種同步加鎖的方式不一樣 = =且看我細細道來
先看看code
package cn.tread; public class TicketDemo { /** * @param args */ public static void main(String[] args) { Person2 p1 = new Person2("haoren"); Thread t1 = new Thread(p1); Thread t2 = new Thread(p1); t1.start(); t2.start(); } } class Person2 implements Runnable { private String name; private int tickets = 5; public Person2(String name) { this.name = name; } //同步代碼塊 需要的鎖是 任意對象~ Object object1 = new Object(); public void run() { for (int i = 0; i < 5; i++) { synchronized (object1) {//object1就是傳說中的鎖,要同步必須使用同一個鎖 if (tickets > 0) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(tickets--); } } } } }
觀察上面的代碼 我們 有了一個總結 同步代碼的鎖可以是任意對象
然後是同步的前提
同步的弊端
然後我們說說同步函數
package cn.java.thread; /* 證明同步函數用的是this這把鎖 */ public class Tickets1 { /** * @param args */ public static void main(String[] args) { /* * GetTickets gt1 = new GetTickets(); GetTickets gt2 = new GetTickets(); * GetTickets gt3 = new GetTickets(); gt1.setName("窗口一"); * gt2.setName("窗口二"); gt3.setName("窗口三"); gt1.start(); gt2.start(); * gt3.start(); */ GetTickets2 gt = new GetTickets2(); Thread th1 = new Thread(gt, "窗口一"); Thread th2 = new Thread(gt, "窗口二"); Thread th3 = new Thread(gt, "窗口三"); th1.start(); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } gt.flag = true; th2.start(); th3.start(); } } class GetTickets2 implements Runnable { private int tickets = 10; boolean flag = false; Object ob = new Object(); public void run() { if (flag) { for (int i = 0; i < 10; i++) { //synchronized (ob) {//如果用ob就無法同步 synchronized (this) { if (tickets > 0) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "賣出" + (tickets--) + "號票"+":同步代碼塊"); } } } } else { for (int i = 0; i < 10; i++) { function(); } } } public synchronized void function() { if (tickets > 0) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "賣出" + (tickets--) + "號票"+":同步函數"); } } } /* * class GetTickets extends Thread{ //private static int tickets = 10; private * int tickets = 10; public void run(){ * * for (int i = 0; i < 10; i++) { if(tickets>0){ * System.out.println(Thread.currentThread().getName()+"賣出"+(tickets--)+"號票"); } * } } } */
通過 觀察我們不難發現
余下的我在下一個分P寫...
Java 線程寶典