Java学习:多线程(2)
?線程中的一些方法
線程加入:public final void join()
等待該線程終止,其他線程才能搶著執行。
練習代碼如下:
1 public static void main(String[] args) { 2 //創建三個線程 3 MyThread mt1 = new MyThread(); 4 MyThread mt2 = new MyThread(); 5 MyThread mt3 = new MyThread(); 6 7 //給線程起名字 8 mt1.setName("劉備"); 9 mt2.setName("曹操"); 10 mt3.setName("孫權"); 11 12 //開啟三個線程 13 mt1.start(); 14 15 //接著讓mt1這個線程設置為加入線程,其他線程就沒有搶占cpu執行權的權利了,只能等待該線程執行完畢之后,才能開始搶占 16 try { 17 mt1.join(); 18 } catch (InterruptedException e) { 19 // TODO Auto-generated catch block 20 e.printStackTrace(); 21 } 22 23 24 mt2.start(); 25 mt3.start(); 26 27 } 線程加入練習線程禮讓:public final void yield()
暫停當時正在執行的縣城對象,并執行其他線程。
作用:讓線程間的執行更和諧,但實際上做不到。
練習代碼下:
?
1 public class MyThread extends Thread{ 2 @Override 3 public void run() { 4 for (int i = 0; i < 100; i++) { 5 System.out.println(getName()+"---"+i); 6 //實現線程禮讓 7 Thread.yield(); 8 } 9 } 10 11 } 線程禮讓?
線程死亡:
public final void stop():直接殺死。
練習代碼如下:
run方法 1 MyThread mt = new MyThread(); 2 3 //開啟線程對象 4 mt.start(); 5 6 //在線程處于睡眠的過程中將他殺死 7 8 try { 9 Thread.sleep(3000); 10 //殺死剛剛開啟的線程 11 //調用stop()方法將線程直接殺死 12 mt.stop();//劃了一條橫線表示該方法已經過時,但是還可以使用 13 } catch (InterruptedException e) { 14 // TODO Auto-generated catch block 15 e.printStackTrace(); 16 } stopTest結果如下:
public void interrupt():直接殺死,在死前還有遺言。
練習代碼:
1 public void run() { 2 //打印一下開始執行的時間 3 System.out.println("開始時間:"+new SimpleDateFormat("HH:mm:ss").format(new Date())); 4 //休眠10秒鐘 5 try { 6 Thread.sleep(10000); 7 } catch (InterruptedException e) { 8 // TODO Auto-generated catch block 9 //e.printStackTrace(); 10 System.out.println("我被殺死了"); 11 } 12 System.out.println("結束時間:"+new SimpleDateFormat("HH:mm:ss").format(new Date())); 13 } run方法 1 MyThread mt = new MyThread(); 2 3 //開啟線程對象 4 mt.start(); 5 6 //在線程處于睡眠的過程中將他殺死 7 8 try { 9 Thread.sleep(3000); 10 //殺死剛剛開啟的線程 11 //interrupt():直接殺死,在死前,還可以有遺言。 12 mt.interrupt();//線程被殺死之后會將后面的代碼執行完畢之后,再死去 13 14 } catch (InterruptedException e) { 15 // TODO Auto-generated catch block 16 e.printStackTrace(); 17 } interruptTest
線程休眠:
static void sleep(lang millis):
在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行),此操作受到系統計時器和調度程序精度和準確性的影響。
線程間通信(生產消費者問題):不同類型線程針對同一個資源操作。我們常見一個Student對象,然后再創建一個設置Student對象的線程和一個獲取Student對象的線程。
1 public class Student { 2 String name; 3 int age; 4 } Student類 public class SetThread implements Runnable{private Student s;private int x=0;public SetThread(Student s){this.s = s;}@Overridepublic void run() {//給學生對象設置姓名和年齡//Student s = new Student();while (true) {synchronized (s) {if (x%2==0) {s.name = "大明";s.age = 14;}else {s.name = "陳小寶";s.age = 12;}x++;}}}} SetStudent 1 public class GetThread implements Runnable{ 2 private Student s; 3 4 public GetThread(Student s){ 5 this.s = s; 6 } 7 @Override 8 public void run() { 9 //獲取線程,獲取學生對象的姓名和年齡 10 //Student s = new Student(); 11 while (true) { 12 synchronized (s) { 13 System.out.println(s.name+"--"+s.age); 14 } 15 } 16 } 17 18 } GetStudent 1 public class StudentDemo { 2 public static void main(String[] args) { 3 //創建一個學生對象 4 Student s = new Student(); 5 6 //創建設置和獲取線程,并開啟線程 7 SetThread st = new SetThread(s); 8 GetThread gt = new GetThread(s); 9 10 Thread t1 = new Thread(st); 11 Thread t2 = new Thread(gt); 12 13 //開啟線程 14 t1.start(); 15 t2.start(); 16 17 } 18 19 } StudentDemo當我們運行這些代碼時我們會發現一些問題,就是陳小寶和大明并不是交替出現的而是一個人出現好多次才出現另一個人。這是因為CPU的運行速的很快,而兩個線程的搶占是隨機的。
用wait方法和notify方法改進上述案例。
1 public class Student { 2 String name; 3 int age; 4 boolean flag;//在這里可以作為對象的一個標記,如果是false說明該對象沒有數據,如果是true說明該對象有數據 5 6 } 改進后的Student類 1 public class SetThread implements Runnable{ 2 private Student s; 3 private int x = 0; 4 5 public SetThread(Student s){ 6 this.s = s; 7 } 8 @Override 9 public void run() { 10 while (true) { 11 synchronized (s) { 12 //判斷該對象此時有沒有數據 13 if (s.flag) { 14 //等待 15 try { 16 s.wait();//設置線程等待,釋放鎖s 17 } catch (InterruptedException e) { 18 // TODO Auto-generated catch block 19 e.printStackTrace(); 20 } 21 } 22 23 if (x%2==0) { 24 s.name = "大明"; 25 s.age = 14; 26 }else { 27 s.name = "陳小寶"; 28 s.age = 13; 29 } 30 x++;//x=1 31 32 //此時對象有數據了 33 s.flag = true; 34 s.notify();//如果有等待的線程就喚醒,如果沒有等待的線程,則沒有任何效果 35 }//在此時釋放鎖對象s 36 } 37 38 } 改進后的SetStudent類 1 public class GetThread implements Runnable{ 2 private Student s; 3 4 public GetThread(Student s){ 5 this.s = s; 6 } 7 8 @Override 9 public void run() { 10 while (true) { 11 synchronized (s) { 12 //判斷對象有沒有數據 13 if (!s.flag) { 14 //等待設置線程給對象設置數據 15 try { 16 s.wait();//獲取線程處于等待狀態,釋放鎖對象s,在哪里跌倒在哪里爬起來 17 } catch (InterruptedException e) { 18 // TODO Auto-generated catch block 19 e.printStackTrace(); 20 } 21 } 22 23 System.out.println(s.name+"--"+s.age); 24 25 //當獲取線程從學生對象中獲取了數據之后,我們就默認他已經沒有數據了,此時我們應該 26 //繼續讓設置線程繼續給學生對象設置信息 27 s.flag = false; 28 s.notify(); 29 } 30 } 31 32 } 33 34 } 改進后的GetStudent類當此程序運行時就不會出現一個人名連續出現好多次的情況了;
結果如下:
這個代碼有一些繞,要細細的揣摩才能想明白。
線程池
為什么要使用線程池?
程序啟動一個新線程成本是比較高的,因為它涉及到要與操作系統進行交互。而使用線程池可以很好的提高性能,
尤其是當程序中要創建大量生存期很短的線程時,更應該考慮使用線程池。
線程池的特點:
線程池里的每一個線程代碼結束后,并不會死亡,而是再次回到線程池中成為空閑狀態,等待下一個對象來使用。
在JDK5之前,我們必須手動實現自己的線程池,從JDK5開始,Java內置支持線程池
?
線程池如何創建?
JDK5新增了一個Executors工廠類來產生線程池,有如下幾個方法
public static ExecutorService newFixedThreadPool(int nThreads)
線程池的使用步驟:
1.創建線程池對象
ExecutorService pool = Executors.newFixedThreadPool(2);
2.創建Runnable實例
MyRunnable my = new MyRunnable();
3.提交Runnable實例
pool.submit(my);
pool.submit(my);
4.關閉線程池
pool.shutdown();
?
練習代碼:
1 public class MyCallable implements Callable{ 2 //也是一個任務,只不過這個任務需要執行的方法是call(),這個方法有返回值 3 @Override 4 public Object call() throws Exception { 5 for (int i = 0; i < 100; i++) { 6 System.out.println(Thread.currentThread().getName()+"---"+i); 7 } 8 return null; 9 } 10 11 } MyCallable? 1 public class ThreadPool { 2 public static void main(String[] args) { 3 //案例2:實現Callable接口實現線程池的使用 4 //1.創建線程池 5 ExecutorService pool = Executors.newFixedThreadPool(2); 6 7 //創建一個任務 8 MyCallable my1 = new MyCallable(); 9 MyCallable my2 = new MyCallable(); 10 11 //3.提交任務 12 pool.submit(my1); 13 pool.submit(my2); 14 15 //4.關閉線程池 16 pool.shutdown(); 17 18 } ThreadPool? 1 public class MyRunnbale implements Runnable { 2 3 @Override 4 public void run() { 5 for (int i = 0; i < 100; i++) { 6 System.out.println(Thread.currentThread().getName()+"---"+i); 7 } 8 9 } 10 11 } MyRunnable 1 public static void main(String[] args) { 2 //線程池如何創建? 3 //1.調用工廠類Executors 4 //的public static ExecutorService newFixedThreadPool(int nThreads),返回一個線程池對象 5 ExecutorService pool = Executors.newFixedThreadPool(2); 6 7 //2.提交給線程池兩個任務,都是打印0-99 8 //創建任務 9 MyRunnbale my1 = new MyRunnbale(); 10 MyRunnbale my2 = new MyRunnbale(); 11 12 //3.提交任務 13 pool.submit(my1); 14 pool.submit(my2); 15 16 //關閉線程池 17 //void shutdown() 18 pool.shutdown(); View Code?
?
定時器
Timer
public Timer()構造
public void schedule(TimerTask task, long delay)延遲多久執行任務
public void schedule(TimerTask task,long delay,long period)延遲多久執行任務,并以后每隔多久執行一次
public boolean cancel()取消這個任務
?
1 public class TimerTest { 2 public static void main(String[] args) { 3 //需求:在10秒鐘后,在控制臺打印一句話,helloworld 4 //public Timer()構造 5 Timer t = new Timer(); 6 7 //public void schedule(TimerTask task, long delay)延遲多久執行任務 8 t.schedule(new MyTimerTask(t), 10000); 9 10 //public void cancel()終止此計時器 11 //t.cancel();//如果在這里關閉的話,我們還沒等任務執行完畢呢,計時器已經被關閉了 12 13 } 14 15 } 16 17 //創建TimerTask的子類 18 class MyTimerTask extends TimerTask{ 19 private Timer t; 20 public MyTimerTask(Timer t){ 21 this.t = t; 22 } 23 24 @Override 25 public void run() { 26 //此計時器任務要執行的操作。 27 System.out.println("helloworld"); 28 t.cancel();//當任務被執行完畢之后,關閉定時器 29 } 30 31 } TimerTask?
轉載于:https://www.cnblogs.com/shaofanglazi/p/6900928.html
總結
以上是生活随笔為你收集整理的Java学习:多线程(2)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode 540 有序数组中的单
- 下一篇: 用Java语言编写的特殊算法