1.收獲
慢慢的java學(xué)習(xí)階段快要進(jìn)入結(jié)束階段赖欣,馬上就要進(jìn)入Andriod階段屑彻,在這段學(xué)習(xí)的期間,說實(shí)話學(xué)到的東西是很多的顶吮,包括沒有在學(xué)校的課堂學(xué)到的東西社牲,在這個(gè)階段自己雖然沒有發(fā)現(xiàn)自己有多大的變化但是我認(rèn)為在這個(gè)階段沒有進(jìn)行而太多的實(shí)際操作,很多的東西還是在理論的水平悴了。不管怎樣自己一定要努力搏恤,希望時(shí)間值得!
2.技術(shù)
(1)進(jìn)程
(2)線程
(3)線程安全
3.技術(shù)的實(shí)際應(yīng)用和實(shí)踐
(1)進(jìn)程
什么是進(jìn)程:
根據(jù)我自己的理解就是正在運(yùn)行的一個(gè)程序 QQ IDE 瀏覽器, 并且系統(tǒng)會(huì)為這個(gè)進(jìn)程分配獨(dú)立的內(nèi)存資源湃交。
可以同時(shí)多個(gè)進(jìn)程運(yùn)行熟空。
(2)線程
什么是線程:
具體執(zhí)行任務(wù)的最小單位,在Andriod中顯示界面稱為UI主線程搞莺,一個(gè)進(jìn)程最少擁有一個(gè)線程 (主線程 運(yùn)行起來就執(zhí)行的線程)息罗,線程之間是共享同一片內(nèi)存資源的(進(jìn)程申請的),線程之間可以通信的(數(shù)據(jù)傳遞:多數(shù)為主線程和子線程)腮敌,每一個(gè)線程都有自己的運(yùn)行回路(生命周期)阱当。
** 線程的生命周期**
狀態(tài)
- NEW:新建 線程剛被創(chuàng)建好
- RUNNABLE:就緒狀態(tài) 只要搶到時(shí)間片就可以運(yùn)行這個(gè)線程
- BLOCKED:阻塞狀態(tài) wait sleep
- WAITING:等待 wait
- TIMED_WAITING:處在TIMED_WAITING的線程,如果特定的事件發(fā)生或者是時(shí)間流逝完畢糜工,都會(huì)恢復(fù)運(yùn)行弊添。
- TERMINATED:終止?fàn)顟B(tài)
線程執(zhí)行
子線程
為什么要?jiǎng)?chuàng)建子線程:
如果在主線程存在又比較耗時(shí)的操作 :下載視頻 上傳文件 數(shù)據(jù)處理 ,這些會(huì)阻塞主線程捌木,后面的任務(wù)必須等待這些任務(wù)執(zhí)行完畢之后才能執(zhí)行油坝,用戶體驗(yàn)比較差,為了不阻塞主線程,需要將耗時(shí)的任務(wù)放在子線程中去處理。
如何創(chuàng)建子線程:
兩種方法:
1.定義一個(gè)類繼承于Thread 實(shí)現(xiàn)run方法
首先看一下Thread的方法
class TestThread extends Thread{
//實(shí)現(xiàn)run方法
//方法里面就是需要具體執(zhí)行的代碼
@Override
public void run() {
//System.out.println(Thread.currentThread().getName());
for(int i=1;i<=100;i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (this != MyClass.tt1) {
if (i == 10) {
try {
MyClass.tt1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
super.run();
}
}
然后再主函數(shù)中創(chuàng)建子線程
static TestThread tt1;
public static void main(String[] args) {
//main方法里面執(zhí)行的代碼 是在主線程里面執(zhí)行的
System.out.println(Thread.currentThread().getName());
//創(chuàng)建對(duì)象
TestThread tt=new TestThread();
//設(shè)置線程名稱
tt.setName("子線程1");
//開啟任務(wù)
tt.start();
//創(chuàng)建對(duì)象
tt1=new TestThread();
//設(shè)置線程名稱
tt1.setName("子線程2");
//開啟任務(wù)
tt1.start();
2.實(shí)現(xiàn)Runnable接口 實(shí)現(xiàn)run方法
- a.創(chuàng)建任務(wù) 創(chuàng)建類實(shí)現(xiàn)Runnable接口
- b.使用Thread為這個(gè)任務(wù)分配線程
- c.開啟任務(wù) start
class TestTheard1 implements Runnable{
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
這里有四種方式
第一種:
//1.接口 抽象方法
//創(chuàng)建一個(gè)任務(wù):創(chuàng)建一個(gè)類來實(shí)現(xiàn)Runnable接口
TestTheard1 TT=new TestTheard1();
//使用Thread操作這個(gè)任務(wù)
Thread T=new Thread(TT);
T.setName("子線程1");
T.start();
Thread T1=new Thread(TT);
T1.setName("子線程2");
T1.start();
第二種:
//這個(gè)任務(wù)只需要使用一次
Thread t=new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
});
t.setName("子線程1");
t.start();
第三種:
//創(chuàng)建線程的同時(shí) 直接開啟線程本身的任務(wù)
//不需要操作線程對(duì)象本身
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}).start();
第四種:
//使用Lambda表達(dá)式
//不建議:閱讀性太差
new Thread(()->{
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}).start();
(3)線程安全
什么是線程安全:
按照自己的理解就是多個(gè)線程操作同一個(gè)資源澈圈,線程無法確定自己什么時(shí)候被阻塞彬檀,導(dǎo)致數(shù)據(jù)錯(cuò)誤。
怎末來解決線程安全問題:
就需要把每個(gè)線程分開來操作同一個(gè)資源瞬女,利用synchronized Lock;(加鎖 解鎖)窍帝,synchronized 同步的監(jiān)聽器 需要一把鎖,任何一個(gè)對(duì)象都有一把鎖(監(jiān)聽器)诽偷。如果多個(gè)線程操作統(tǒng)一的代碼塊
模板: synchronized(監(jiān)聽器/對(duì)象/鎖){需要同步的代碼}
1.同步代碼塊
- synchronized (監(jiān)聽器/對(duì)象/鎖){需要同步的代碼}
2.同步方法 同步監(jiān)聽器是當(dāng)前的對(duì)象本身
- 必須確保多個(gè)對(duì)象調(diào)用的同步方法是操作的是同一個(gè)對(duì)象
- public synchronized void test() 本質(zhì)就是同步代碼塊n
- 等價(jià)于synchronize(this) {test() ;}
實(shí)際應(yīng)用:
功能:火車站買票坤学,全國的買票系統(tǒng) 就一個(gè),重慶 上海
代碼:
首先我們要?jiǎng)?chuàng)建一個(gè)類繼承Runnable报慕,并實(shí)現(xiàn)run方法
synchronized鎖:
//用于買票的任務(wù)
class Ticket implements Runnable {
//定義所有車票的數(shù)量
public static int num = 100;
String name;
public Ticket(String name) {
this.name = name;
}
@Override
public void run() {
synchronized (this) {
test();
}
}
public void test() {
for (int i = 1; i <= 100; i++) {
//判斷有沒有票
if (num > 0) {
System.out.println(name + " 出票:" + (101 - num));
num--;
} else {
break;
}
}
}
}
}
然后在主函數(shù)中開始線程
Ticket ticket1=new Ticket("上海");
Ticket ticket=new Ticket("重慶");
Thread t1=new Thread(ticket);
Thread t2=new Thread(ticket1);
t2.start();
t1.start();
交替進(jìn)行購票
ublic Ticket(String name) {
this.name = name;
}
static final Object obj = new Object();
public void run() {
synchronized (this) {
test();
}
}
public void test() {
for (int i = 1; i <= 100; i++) {
//判斷有沒有票
if (num > 0) {
System.out.println(name + " 出票:" + (101 - num));
num--;
try {
//當(dāng)前線程等待
obj.notify()深浮;
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//通知其他的線程執(zhí)行
}
}else{
break;
}
}
}
}
第二種鎖:
可重入的鎖reentrantLock.
與上面的不同之處就是是實(shí)現(xiàn)aianrun方法不同
static ReentrantLock reentrantLock = new ReentrantLock();
Condition condition = reentrantLock.newCondition();
@Override
ublic void run() {
for(int i=1;i<=100;i++){
//判斷有沒有票
reentrantLock.lock();
//需要同步代碼塊
if(num>0){
System.out.println(name+" 出票:"+(101-num));
num--;
}else{
break;
}
reentrantLock.unlock();
}
}
}