JAVA多线程学习(一)
一、什么是多線程?
很顯然,一隨便編敲一段簡單的小代碼,從main方法開始運行,計算機是一條一條地從上而下的串行執(zhí)行程序。那如果我們要同時執(zhí)行兩個任務(wù)呢?就比如你用瀏覽器上網(wǎng)看網(wǎng)頁的時候,你還能同時登QQ,還能同時下載電影……這些任務(wù)都是并行執(zhí)行的。在計算機的任務(wù)管理器里可以看到一個一個的正在運行的程序任務(wù),這些程序就是一個個一個的進程,而大多數(shù)進程下面都已多條線程同時執(zhí)行,所以,多線程其實就是多個任務(wù)在同時執(zhí)行。
雖然是多線程,但是CPU執(zhí)行命令仍然是一條一條執(zhí)行的。然而計算機CPU只有一個,雖然多核計算機能夠有虛擬多CPU的技術(shù)(這是我自己對多核CPU的理解,不夠準確請見諒),但是相對于計算機要實現(xiàn)的線程數(shù)量,簡直少的可憐。所以,當多線程在硬件實現(xiàn)的時候,CPU的處理方式是進行分時處理(TDMA時分多址有沒有!!?)。什么意思呢,就是在一段時間執(zhí)行這一條線程,一段時間執(zhí)行另外一條線程,所有的具有執(zhí)行資格的線程進行隨機的獲得CPU的執(zhí)行權(quán)。CPU的運算速度快的驚人,因此我們感覺上其實就是多線程在并發(fā)執(zhí)行了。
二、JAVA中多線程的使用,Thread類
“一切皆對象”在JAVA語言中是一個永恒不變的定理,自然線程這玩意同樣有個對象進行包裝。那就是Thread類。這個對象實現(xiàn)了一個Runnable接口,這個接口很簡單,就一個run方法。
對于要多線程執(zhí)行任務(wù),可以通過如下兩種方法來實現(xiàn)多線程:
1、繼承Thread類
通過將要實現(xiàn)的任務(wù)封裝成方法,再封裝成對象,然后繼承Thread類,將任務(wù)方法寫進run方法之中,在再父線程中用start方法啟動就可以了。比如如下開啟一個線程的代碼
package com.qyz.thread;public class ThreadDemo1 {public static void main(String[] args) {Thread t1 = new Demo("第一個線程");//start()開啟線程 t1.start();//輸出:第一個線程:被打開了 } } //繼承了Thread的對象 class Demo extends Thread{public Demo(String name){//父類構(gòu)造方法中可以給線程命名super(name);}//重寫run方法 @Overridepublic void run(){//打印線程名稱System.out.println(Thread.currentThread().getName() + ":被打開了");} }?
?
2、通過實現(xiàn)Runnable接口
方法一的線程開啟方法有一個問題,就是當一個類的的繼承體系結(jié)構(gòu)之中,只有部分子類需要開啟新的線程執(zhí)行任務(wù),但由于是單繼承的,繼承了某個父類的子類不可能再繼承Thread方法,因此只有通過實現(xiàn)
Runnable方法來開啟線程。
1、某個類實現(xiàn)Runnable,并重寫run方法,封裝需要新開啟線程實現(xiàn)的任務(wù)。2、新建Thread(Runnable target,name)對象。將Runnable對象封裝進線程對象中。3、開啟線程start()
1 package com.qyz.thread; 2 3 public class ThreadDemo2 { 4 5 public static void main(String[] args) { 6 Thread t1 = new Thread(new Demo2(),"第二個線程"); 7 //start()開啟線程 8 t1.start(); 9 //輸出:第二個線程:被打開了 10 } 11 } 12 //實現(xiàn)了Runnable接口的對象 13 class Demo2 implements Runnable{ 14 //重寫run方法 15 @Override 16 public void run(){ 17 //打印線程名稱 18 System.out.println(Thread.currentThread().getName() + ":被打開了"); 19 } 20 }?
三、多線程之間的同步問題
多線程好嗎?當然好,但是會有一個問題需要注意!那就是同步問題。在多個線程訪問同一對象數(shù)據(jù)時?有多條操作命令,本來想的是等一個線程操作完該對象后,另外一個線程再操作,但是由于CPU是隨機分時執(zhí)行線程,因此有可能當一個線程對共享對象操作到一半時,CPU就切向另外一個線程,導(dǎo)致出現(xiàn)意外的輸出結(jié)果。這樣的問題一半很難排查,因此需要在編寫代碼的時候多加注意!
沒有同步的買賣票事例
1 package com.qyz.thread; 2 3 public class TickerDemo1 { 4 public static void main(String[] args) { 5 SaleTicket st = new SaleTicket(); 6 //實現(xiàn)3個線程 7 Thread t1 = new Thread(st, "1號賣票員"); 8 Thread t2 = new Thread(st, "2號賣票員"); 9 Thread t3 = new Thread(st, "3號賣票員"); 10 //開啟線程 11 t1.start(); 12 t2.start(); 13 t3.start(); 14 } 15 } 16 class SaleTicket implements Runnable{ 17 //總共100張票 18 private int num = 100; 19 @Override 20 public void run() { 21 while(this.num > 0){ 22 //這個代碼太簡單,所以讓線程睡一會,突出同步問題 23 try {Thread.sleep(10);} catch (Exception e) {} 24 System.out.println(Thread.currentThread().getName() + "******" + num--); 25 } 26 } 27 }?
本來不該出現(xiàn)的0號票出現(xiàn)了,意外情況
解決方法:加鎖
多線程中的鎖其實就像一扇門,一個線程進去之后,把門鎖上,另外一個線程就不能進來,直到門里面的線程執(zhí)行完畢出來。
JAVA中實現(xiàn)同步鎖通過關(guān)鍵字synchronized,有以下方法
1、同步代碼塊,需要同步的命令封裝進一個代碼塊中,加上一個對象做鎖即可
1 class SaleTicket implements Runnable{ 2 //總共100張票 3 private int num = 100; 4 //一個object對象充當鎖 5 private Object lock = new Object(); 6 @Override 7 public void run() { 8 while(true){ 9 //同步代碼塊封裝 10 synchronized (lock) { 11 if(this.num > 0){ 12 //這個代碼太簡單,所以讓線程睡一會,突出同步問題 13 try {Thread.sleep(10);} catch (Exception e) {} 14 System.out.println(Thread.currentThread().getName() + "******" + num--); 15 }else 16 break; 17 } 18 } 19 } 20 }?
?
?輸出如下
問題解決!
2、同步函數(shù)
函數(shù)是一種封裝,代碼塊也是一種封裝,那能不能結(jié)合在一起呢?sure!那就是通過關(guān)鍵字將將方法變成同步函數(shù)。
1 class SaleTicket implements Runnable{ 2 //總共100張票 3 private int num = 100; 4 @Override 5 public void run() { 6 while(true){ 7 this.sale(); 8 } 9 } 10 //通過封裝成同步函數(shù)來實現(xiàn) 11 private synchronized void sale(){ 12 if(this.num > 0){ 13 //這個代碼太簡單,所以讓線程睡一會,突出同步問題 14 try {Thread.sleep(10);} catch (Exception e) {} 15 System.out.println(Thread.currentThread().getName() + "******" + num--); 16 } 17 } 18 }?
成功解決!
轉(zhuǎn)載于:https://www.cnblogs.com/njupt-Qsimple/p/5618491.html
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的JAVA多线程学习(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于MySQL的各种总结
- 下一篇: radio选中