A:Java程序運行原理java
B:JVM的啓動是多線程的嗎安全
package com.heima.thread; public class Demo1_Thread { /** * @param args * 證實jvm是多線程的 */ public static void main(String[] args) { for(int i = 0; i < 100000; i++) { new Demo(); } for(int i = 0; i < 10000; i++) { System.out.println("我是主線程的執行代碼"); } } } class Demo { @Override public void finalize() { System.out.println("垃圾被清掃了"); } }
1.繼承Thread服務器
public class Demo2_Thread { /** * @param args */ public static void main(String[] args) { MyThread mt = new MyThread(); //4,建立自定義類的對象 mt.start(); //5,開啓線程 for(int i = 0; i < 3000; i++) { System.out.println("bb"); } } } class MyThread extends Thread { //1,定義類繼承Thread public void run() { //2,重寫run方法 for(int i = 0; i < 3000; i++) { //3,將要執行的代碼,寫在run方法中 System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa"); } } }
package com.heima.thread; public class Demo2_Thread { /** * @param args */ public static void main(String[] args) { MyThread mt = new MyThread(); //4,建立Thread類的子類對象 mt.start(); //5,開啓線程 for(int i = 0; i < 1000; i++) { System.out.println("bb"); } } } class MyThread extends Thread { //1,繼承Thread public void run() { //2,重寫run方法 for(int i = 0; i < 1000; i++) { //3,將要執行的代碼寫在run方法中 System.out.println("aaaaaaaaaaaa"); } } }
2.實現Runnable多線程
調用start()開啓新線程, 內部會自動調用Runnable的run()方法併發
public class Demo3_Runnable { /** * @param args */ public static void main(String[] args) { MyRunnable mr = new MyRunnable(); //4,建立自定義類對象 //Runnable target = new MyRunnable(); Thread t = new Thread(mr); //5,將其看成參數傳遞給Thread的構造函數 t.start(); //6,開啓線程 for(int i = 0; i < 3000; i++) { System.out.println("bb"); } } } class MyRunnable implements Runnable { //1,自定義類實現Runnable接口 @Override public void run() { //2,重寫run方法 for(int i = 0; i < 3000; i++) { //3,將要執行的代碼,寫在run方法中 System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa"); } } }
package com.heima.thread; public class Demo3_Thread { /** * @param args */ public static void main(String[] args) { MyRunnable mr = new MyRunnable(); //4,建立Runnable的子類對象 //Runnable target = mr; mr = 0x0011 Thread t = new Thread(mr); //5,將其看成參數傳遞給Thread的構造函數 t.start(); //6,開啓線程 for(int i = 0; i < 1000; i++) { System.out.println("bb"); } } } class MyRunnable implements Runnable { //1,定義一個類實現Runnable @Override public void run() { //2,重寫run方法 for(int i = 0; i < 1000; i++) { //3,將要執行的代碼寫在run方法中 System.out.println("aaaaaaaaaaaa"); } } }
package com.heima.thread; public class Demo4_Thread { /** * @param args */ public static void main(String[] args) { new Thread() { //1,繼承Thread類 public void run() { //2,重寫run方法 for(int i = 0; i < 1000; i++) { //3,將要執行的代碼寫在run方法中 System.out.println("aaaaaaaaaaaaaa"); } } }.start(); //4,開啓線程 new Thread(new Runnable() { //1,將Runnable的子類對象傳遞給Thread的構造方法 public void run() { //2,重寫run方法 for(int i = 0; i < 1000; i++) { //3,將要執行的代碼寫在run方法中 System.out.println("bb"); } } }).start(); //4,開啓線程 } }
查看源碼的區別:jvm
繼承Threadide
繼承Thread類函數
new Thread() { //1,new 類(){}繼承這個類 public void run() { //2,重寫run方法 for(int i = 0; i < 3000; i++) { //3,將要執行的代碼,寫在run方法中 System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa"); } } }.start();
實現Runnable接口ui
new Thread(new Runnable(){ //1,new 接口(){}實現這個接口 public void run() { //2,重寫run方法 for(int i = 0; i < 3000; i++) { //3,將要執行的代碼,寫在run方法中 System.out.println("bb"); } } }).start();
2.設置名字this
new Thread("xxx") { public void run() { for(int i = 0; i < 1000; i++) { System.out.println(this.getName() + "....aaaaaaaaaaaaaaaaaaaaaaa"); } } }.start(); new Thread("yyy") { public void run() { for(int i = 0; i < 1000; i++) { System.out.println(this.getName() + "....bb"); } } }.start();
Thread t1 = new Thread() { public void run() { for(int i = 0; i < 1000; i++) { System.out.println(this.getName() + "....aaaaaaaaaaaaaaaaaaaaaaa"); } } }; Thread t2 = new Thread() { public void run() { for(int i = 0; i < 1000; i++) { System.out.println(this.getName() + "....bb"); } } }; t1.setName("芙蓉姐姐"); t2.setName("鳳姐"); t1.start(); t2.start();
package com.heima.threadmethod; public class Demo1_Name { /** * @param args */ public static void main(String[] args) { //demo1(); Thread t1 = new Thread() { public void run() { //this.setName("張三"); System.out.println(this.getName() + "....aaaaaaaaaaaaa"); } }; Thread t2 = new Thread() { public void run() { //this.setName("李四"); System.out.println(this.getName() + "....bb"); } }; t1.setName("張三"); t2.setName("李四"); t1.start(); t2.start(); } public static void demo1() { new Thread("芙蓉姐姐") { //經過構造方法給name賦值 public void run() { System.out.println(this.getName() + "....aaaaaaaaa"); } }.start(); new Thread("鳳姐") { public void run() { System.out.println(this.getName() + "....bb"); } }.start(); } }
Thread.currentThread(), 主線程也能夠獲取
new Thread(new Runnable() { public void run() { for(int i = 0; i < 1000; i++) { System.out.println(Thread.currentThread().getName() + "...aaaaaaaaaaaaaaaaaaaaa"); } } }).start(); new Thread(new Runnable() { public void run() { for(int i = 0; i < 1000; i++) { System.out.println(Thread.currentThread().getName() + "...bb"); } } }).start(); Thread.currentThread().setName("我是主線程"); //獲取主函數線程的引用,並更名字 System.out.println(Thread.currentThread().getName()); //獲取主函數線程的引用,並獲取名字
package com.heima.threadmethod; public class Demo2_CurrentThread { /** * @param args */ public static void main(String[] args) { new Thread() { public void run() { System.out.println(getName() + "....aaaaaa"); } }.start(); new Thread(new Runnable() { public void run() { //Thread.currentThread()獲取當前正在執行的線程 System.out.println(Thread.currentThread().getName() + "...bb"); } }).start(); Thread.currentThread().setName("我是主線程"); System.out.println(Thread.currentThread().getName()); } }
Thread.sleep(毫秒,納秒), 控制當前線程休眠若干毫秒1秒= 1000毫秒 1秒 = 1000 * 1000 * 1000納秒 1000000000
new Thread() { public void run() { for(int i = 0; i < 10; i++) { System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); new Thread() { public void run() { for(int i = 0; i < 10; i++) { System.out.println(getName() + "...bb"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start();
package com.heima.threadmethod; public class Demo3_Sleep { /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { //demo1(); new Thread() { public void run() { for(int i = 0; i < 10; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + "...aaaaaaaaaa"); } } }.start(); new Thread() { public void run() { for(int i = 0; i < 10; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + "...bb"); } } }.start(); } public static void demo1() throws InterruptedException { for(int i = 20; i >= 0; i--) { Thread.sleep(1000); System.out.println("倒計時第" +i + "秒"); } } }
setDaemon(), 設置一個線程爲守護線程, 該線程不會單獨執行, 當其餘非守護線程都執行結束後, 自動退出
Thread t1 = new Thread() { public void run() { for(int i = 0; i < 50; i++) { System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread t2 = new Thread() { public void run() { for(int i = 0; i < 5; i++) { System.out.println(getName() + "...bb"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }; t1.setDaemon(true); //將t1設置爲守護線程 t1.start(); t2.start();
package com.heima.threadmethod; public class Demo4_Daemon { /** * @param args * 守護線程 */ public static void main(String[] args) { Thread t1 = new Thread() { public void run() { for(int i = 0; i < 2; i++) { System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaa"); } } }; Thread t2 = new Thread() { public void run() { for(int i = 0; i < 50; i++) { System.out.println(getName() + "...bb"); } } }; t2.setDaemon(true); //設置爲守護線程 t1.start(); t2.start(); } }
join(int), 能夠等待指定的毫秒以後繼續
final Thread t1 = new Thread() { public void run() { for(int i = 0; i < 50; i++) { System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread t2 = new Thread() { public void run() { for(int i = 0; i < 50; i++) { if(i == 2) { try { //t1.join(); //插隊,加入 t1.join(30); //加入,有固定的時間,過了固定時間,繼續交替執行 Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(getName() + "...bb"); } } }; t1.start(); t2.start();
package com.heima.threadmethod; public class Demo5_Join { /** * @param args * join(), 當前線程暫停, 等待指定的線程執行結束後, 當前線程再繼續 */ public static void main(String[] args) { final Thread t1 = new Thread() { public void run() { for(int i = 0; i < 10; i++) { System.out.println(getName() + "...aaaaaaaaaaaaa"); } } }; Thread t2 = new Thread() { public void run() { for(int i = 0; i < 10; i++) { if(i == 2) { try { //t1.join(); t1.join(1); //插隊指定的時間,過了指定時間後,兩條線程交替執行 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(getName() + "...bb"); } } }; t1.start(); t2.start(); } }
package com.heima.threadmethod; public class Demo6_Yield { /** * yield讓出cpu禮讓線程 */ public static void main(String[] args) { new MyThread().start(); new MyThread().start(); } } class MyThread extends Thread { public void run() { for(int i = 1; i <= 1000; i++) { if(i % 10 == 0) { Thread.yield(); //讓出CPU } System.out.println(getName() + "..." + i); } } }
package com.heima.threadmethod; public class Demo7_Priority { /** * @param args */ public static void main(String[] args) { Thread t1 = new Thread(){ public void run() { for(int i = 0; i < 100; i++) { System.out.println(getName() + "...aaaaaaaaa" ); } } }; Thread t2 = new Thread(){ public void run() { for(int i = 0; i < 100; i++) { System.out.println(getName() + "...bb" ); } } }; //t1.setPriority(10); 設置最大優先級 //t2.setPriority(1); t1.setPriority(Thread.MIN_PRIORITY); //設置最小的線程優先級 t2.setPriority(Thread.MAX_PRIORITY); //設置最大的線程優先級 t1.start(); t2.start(); } }
2.同步代碼塊
多個同步代碼塊若是使用相同的鎖對象, 那麼他們就是同步的
class Printer { Demo d = new Demo(); public static void print1() { synchronized(d){ //鎖對象能夠是任意對象,可是被鎖的代碼須要保證是同一把鎖,不能用匿名對象 System.out.print("黑"); System.out.print("馬"); System.out.print("程"); System.out.print("序"); System.out.print("員"); System.out.print("\r\n"); } } public static void print2() { synchronized(d){ System.out.print("傳"); System.out.print("智"); System.out.print("播"); System.out.print("客"); System.out.print("\r\n"); } } }
package com.heima.syn; public class Demo1_Synchronized { /** * @param args * 同步代碼塊 */ public static void main(String[] args) { final Printer p = new Printer(); new Thread() { public void run() { while(true) { p.print1(); } } }.start(); new Thread() { public void run() { while(true) { p.print2(); } } }.start(); } } class Printer { Demo d = new Demo(); public void print1() { //synchronized(new Demo()) { //同步代碼塊,鎖機制,鎖對象能夠是任意的 synchronized(d) { System.out.print("黑"); System.out.print("馬"); System.out.print("程"); System.out.print("序"); System.out.print("員"); System.out.print("\r\n"); } } public void print2() { //synchronized(new Demo()) { //鎖對象不能用匿名對象,由於匿名對象不是同一個對象 synchronized(d) { System.out.print("傳"); System.out.print("智"); System.out.print("播"); System.out.print("客"); System.out.print("\r\n"); } } } class Demo{}
package com.heima.syn; public class Demo2_Synchronized { /** * @param args * 同步代碼塊 */ public static void main(String[] args) { final Printer2 p = new Printer2(); new Thread() { public void run() { while(true) { p.print1(); } } }.start(); new Thread() { public void run() { while(true) { p.print2(); } } }.start(); } } class Printer2 { Demo d = new Demo(); //非靜態的同步方法的鎖對象是神馬? //答:非靜態的同步方法的鎖對象是this //靜態的同步方法的鎖對象是什麼? //是該類的字節碼對象 public static synchronized void print1() { //同步方法只須要在方法上加synchronized關鍵字便可 System.out.print("黑"); System.out.print("馬"); System.out.print("程"); System.out.print("序"); System.out.print("員"); System.out.print("\r\n"); } public static void print2() { //synchronized(new Demo()) { //鎖對象不能用匿名對象,由於匿名對象不是同一個對象 synchronized(Printer2.class) { System.out.print("傳"); System.out.print("智"); System.out.print("播"); System.out.print("客"); System.out.print("\r\n"); } } }
使用synchronized關鍵字修飾一個方法, 該方法中全部的代碼都是同步的
class Printer { public static void print1() { synchronized(Printer.class){ //鎖對象能夠是任意對象,可是被鎖的代碼須要保證是同一把鎖,不能用匿名對象 System.out.print("黑"); System.out.print("馬"); System.out.print("程"); System.out.print("序"); System.out.print("員"); System.out.print("\r\n"); } } /* * 非靜態同步函數的鎖是:this * 靜態的同步函數的鎖是:字節碼對象 */ public static synchronized void print2() { System.out.print("傳"); System.out.print("智"); System.out.print("播"); System.out.print("客"); System.out.print("\r\n"); } }
使用同步技術能夠解決這種問題, 把操做數據的代碼進行同步, 不要多個線程一塊兒操做
public class Demo2_Synchronized { /** * @param args * 需求:鐵路售票,一共100張,經過四個窗口賣完. */ public static void main(String[] args) { TicketsSeller t1 = new TicketsSeller(); TicketsSeller t2 = new TicketsSeller(); TicketsSeller t3 = new TicketsSeller(); TicketsSeller t4 = new TicketsSeller(); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t4.setName("窗口4"); t1.start(); t2.start(); t3.start(); t4.start(); } } class TicketsSeller extends Thread { private static int tickets = 100; static Object obj = new Object(); public TicketsSeller() { super(); } public TicketsSeller(String name) { super(name); } public void run() { while(true) { synchronized(obj) { if(tickets <= 0) break; try { Thread.sleep(10);//線程1睡,線程2睡,線程3睡,線程4睡 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + "...這是第" + tickets-- + "號票"); } } } }
package com.heima.syn; public class Demo3_Ticket { /** * 需求:鐵路售票,一共100張,經過四個窗口賣完. */ public static void main(String[] args) { new Ticket().start(); new Ticket().start(); new Ticket().start(); new Ticket().start(); } } class Ticket extends Thread { private static int ticket = 100; //private static Object obj = new Object(); //若是用引用數據類型成員變量看成鎖對象,必須是靜態的 public void run() { while(true) { synchronized(Ticket.class) { if(ticket <= 0) { break; } try { Thread.sleep(10); //線程1睡,線程2睡,線程3睡,線程4睡 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + "...這是第" + ticket-- + "號票"); } } } }
package com.heima.syn; public class Demo4_Ticket { /** * @param args * 火車站賣票的例子用實現Runnable接口 */ public static void main(String[] args) { MyTicket mt = new MyTicket(); new Thread(mt).start(); new Thread(mt).start(); new Thread(mt).start(); new Thread(mt).start(); /*Thread t1 = new Thread(mt); //屢次啓動一個線程是非法的 t1.start(); t1.start(); t1.start(); t1.start();*/ } } class MyTicket implements Runnable { private int tickets = 100; @Override public void run() { while(true) { synchronized(this) { if(tickets <= 0) { break; } try { Thread.sleep(10); //線程1睡,線程2睡,線程3睡,線程4睡 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "...這是第" + tickets-- + "號票"); } } } }
多線程同步的時候, 若是同步代碼嵌套, 使用相同鎖, 就有可能出現死鎖
儘可能不要嵌套使用
private static String s1 = "筷子左"; private static String s2 = "筷子右"; public static void main(String[] args) { new Thread() { public void run() { while(true) { synchronized(s1) { System.out.println(getName() + "...拿到" + s1 + "等待" + s2); synchronized(s2) { System.out.println(getName() + "...拿到" + s2 + "開吃"); } } } } }.start(); new Thread() { public void run() { while(true) { synchronized(s2) { System.out.println(getName() + "...拿到" + s2 + "等待" + s1); synchronized(s1) { System.out.println(getName() + "...拿到" + s1 + "開吃"); } } } } }.start(); }
package com.heima.syn; public class Demo5_DeadLock { /** * @param args */ private static String s1 = "筷子左"; private static String s2 = "筷子右"; public static void main(String[] args) { new Thread() { public void run() { while(true) { synchronized(s1) { System.out.println(getName() + "...獲取" + s1 + "等待" + s2); synchronized(s2) { System.out.println(getName() + "...拿到" + s2 + "開吃"); } } } } }.start(); new Thread() { public void run() { while(true) { synchronized(s2) { System.out.println(getName() + "...獲取" + s2 + "等待" + s1); synchronized(s1) { System.out.println(getName() + "...拿到" + s1 + "開吃"); } } } } }.start(); } }