線程和進(jìn)程
進(jìn)程
是一個(gè)獨(dú)立的程序郭赐,要占用系統(tǒng)資源(CPU 內(nèi)存)只祠。
特點(diǎn):
a. 獨(dú)立性:不同的進(jìn)程之間是相互獨(dú)立的涝滴。數(shù)據(jù)也是不共享的。
b. 動(dòng)態(tài)性:進(jìn)程在系統(tǒng)中鞋吉,運(yùn)行是一個(gè)動(dòng)態(tài)的粮彤。是隨著系統(tǒng)一起運(yùn)作的蜜唾。
c. 并發(fā)性:多個(gè)進(jìn)程(程序)可以同時(shí)在電腦中運(yùn)行仅醇,互不影響。
線程
是進(jìn)程的(程序)的組成部分昼钻,一個(gè)進(jìn)程(程序)可以同時(shí)執(zhí)行多個(gè)線程掸屡。如一個(gè)軟件的多個(gè)功能。然评。仅财。
線程的執(zhí)行是【搶占式】。多個(gè)線程在同一個(gè)進(jìn)程(程序)中運(yùn)行時(shí)碗淌,會(huì)搶占當(dāng)前進(jìn)程的資源盏求,CPU在不同的線程中間來(lái)回切換抖锥。切換的速度超過(guò)了肉眼識(shí)別,也就是說(shuō)當(dāng)一個(gè)線程執(zhí)行時(shí)碎罚,其他線程會(huì)掛起等待磅废。
java程序中,至少有兩個(gè)線程荆烈,一個(gè)是main函數(shù)拯勉,另一個(gè)就是垃圾回收機(jī)制
線程和進(jìn)程的區(qū)別
1、一個(gè)程序只有一個(gè)進(jìn)程憔购。
2宫峦、一個(gè)進(jìn)程可以有多個(gè)線程,但是至少需要一個(gè)線程玫鸟,否則進(jìn)程無(wú)意義导绷。
3、進(jìn)程五共享資源屎飘,但是線程是會(huì)共享資源
4妥曲、系統(tǒng)打開(kāi)程序(進(jìn)程),需要給當(dāng)前的進(jìn)程(程序)分配新的對(duì)應(yīng)的系統(tǒng)資源枚碗,效率略低逾一。而線程的創(chuàng)建是進(jìn)程中铸本,不需要系統(tǒng)操作肮雨,所以線程的并發(fā)要比進(jìn)程效率高。
5箱玷、系統(tǒng)打開(kāi)進(jìn)程(程序)沒(méi)有創(chuàng)建線程快怨规,操作簡(jiǎn)單,效率高一點(diǎn)锡足。
線程的好處和壞處
好處:
1波丰、可以讓程序同時(shí)執(zhí)行不同的任務(wù)
2、可以提高系統(tǒng)資源利用率
壞處:
1舶得、線程安全問(wèn)題掰烟,共享資源問(wèn)題。迭代器
// 在迭代器中執(zhí)行刪除操作
while(it.hasNext()){
System.out.println(it.next());
list.remove(2);// 報(bào)錯(cuò)沐批,因?yàn)榇司浜偷鞅旧矶际蔷€程
}
2纫骑、增加CPU負(fù)擔(dān)
3、降低其他程序的CPU執(zhí)行占用率
4九孩、容易出現(xiàn)死鎖
創(chuàng)建線程的方式一
package com.thread;
/**
* 創(chuàng)建線程的第一種方式:
* 1先馆、自定義線程繼承類Thread類
* 2、需要【重寫(xiě)】Thread類內(nèi)的run方法躺彬,把需要執(zhí)行的自定義線程放到run方法內(nèi)
*/
class MyThread extends Thread{
// 重寫(xiě)run方法
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("自定義線程Thread類:"+i);
}
}
}
public class Demo01 {
public static void main(String[] args) {
// 1煤墙、創(chuàng)建自定義線程對(duì)象
MyThread mt = new MyThread();
// 2梅惯、啟動(dòng)線程
// mt.run();// 直接調(diào)用run方法,只是調(diào)用了一個(gè)普通方法仿野,而不是調(diào)用了線程
mt.start();// start方法執(zhí)行線程铣减,會(huì)和其他線程搶占資源,具體表現(xiàn)為每次輸出的順序不定
for (int i = 0; i < 10; i++) {
System.out.println("main線程:"+i);
}
}
}
線程中常用的方法
1设预、Thread(String name);初始化線程的名字徙歼,屬于線程的一個(gè)構(gòu)造方法
2、setName(String name); 設(shè)置線程的名字
3鳖枕、getName(String name); 獲取線程的名字
4魄梯、static sleep(int ms); 靜態(tài)方法,
* 需要用Thread類名來(lái)調(diào)用的方法宾符,讓線程進(jìn)入休眠狀態(tài)酿秸,指定時(shí)間(毫秒)
* 【誰(shuí)執(zhí)行,誰(shuí)休眠】
*
5魏烫、static Thread currentThread(); 靜態(tài)方法
* 需要用Thread類名掉用辣苏,返回當(dāng)前線程
* 【誰(shuí)執(zhí)行,誰(shuí)返回】
*
6哄褒、setPriority(int new newPriority):設(shè)置當(dāng)前線程的優(yōu)先級(jí)稀蟋,優(yōu)先級(jí)范圍是1~10,默認(rèn)5
7呐赡、getPriority(); 返回當(dāng)前線程的優(yōu)先級(jí)退客,只是提高執(zhí)行概率,不是百分百根據(jù)優(yōu)先級(jí)執(zhí)行
代碼實(shí)例
package com.thread;
/**
* 線程中常用的方法
* 1链嘀、Thread(String name);初始化線程的名字萌狂,屬于線程的一個(gè)構(gòu)造方法
* 2、setName(String name); 設(shè)置線程的名字
* 3怀泊、getName(String name); 獲取線程的名字
*
* 4茫藏、static sleep(int ms); 靜態(tài)方法,
* 需要用Thread類名來(lái)調(diào)用的方法霹琼,讓線程進(jìn)入休眠狀態(tài)务傲,指定時(shí)間(毫秒)
* 【誰(shuí)執(zhí)行,誰(shuí)休眠】
*
* 5枣申、static Thread currentThread(); 靜態(tài)方法
* 需要用Thread類名調(diào)用售葡,返回當(dāng)前線程
* 【誰(shuí)執(zhí)行,誰(shuí)返回】
*
* 6糯而、setPriority(int new newPriority):設(shè)置當(dāng)前線程的優(yōu)先級(jí)天通,優(yōu)先級(jí)范圍是1~10,默認(rèn)5
* 7熄驼、getPriority(); 返回當(dāng)前線程的優(yōu)先級(jí)像寒,只是提高執(zhí)行概率烘豹,不是百分百根據(jù)優(yōu)先級(jí)執(zhí)行
*
* Thread[main,5,main]==
* Thread[線程名,優(yōu)先級(jí),線程組]
*/
public class Demo02 extends Thread{
/*
* super調(diào)用了父類Thread的方法
* public Thread(String name) {
init(null, null, name, 0);
}
*/
public Demo02(String name1){
super(name1);
}
// 自定義線程
@Override
public void run() {
System.out.println("自定義線程:"+Thread.currentThread());
//5、static Thread currentThread();此時(shí)自定義線程線程
Thread currentThread = Thread.currentThread();
System.out.println("自定義線程:"+currentThread.getName());
for (int i = 0; i <20; i++) {
System.out.println("自定義線程:"+i);
/*
* 這個(gè)方法是繼承而來(lái)诺祸,而父類的run方法沒(méi)有拋出異常所以只能捕獲携悯,而不能拋出
* 在其他方法中,使用Thread.sleep可以捕獲或者拋出異常筷笨,而run方法中憔鬼,只能捕獲
*
* 因?yàn)椋? * 在Java語(yǔ)法中,重寫(xiě)父類的方法胃夏,要求和父類方法的聲明是一致的轴或。如:
* public static void test()
* 父類方法中,沒(méi)有拋出任何異常仰禀,那么子類的方法如果出現(xiàn)異常照雁,也不能拋出,只能捕獲
*/
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
// 創(chuàng)建自定義線程類對(duì)象
//1答恶、Thread(String name);初始化線程的名字饺蚊,屬于線程的一個(gè)構(gòu)造方法
Demo02 d02 = new Demo02("AAAA");
// 5、static Thread currentThread() 此時(shí)是main線程
Thread currentThread = Thread.currentThread();
// 設(shè)置優(yōu)先級(jí)悬嗓,只是影響執(zhí)行概率污呼,而不是真的優(yōu)先
currentThread.setPriority(1);
System.out.println("當(dāng)前線程:"+currentThread());
System.out.println("當(dāng)前線程:"+currentThread.getName());
//3、getName(String name); 獲取線程的名字
System.out.println(d02.getName());
//2包竹、setName(String name); 設(shè)置線程的名字
d02.setName("BBBB");
//6燕酷、setPriority(int new newPriority):設(shè)置當(dāng)前線程的優(yōu)先級(jí),優(yōu)先級(jí)范圍是1~10映企,默認(rèn)5
d02.setPriority(10);
System.out.println(d02.getName());
// 啟動(dòng)線程不是調(diào)用run方法悟狱,而是執(zhí)行start()
d02.start();
for (int i = 0; i <20; i++) {
System.out.println("main線程:"+i);
Thread.sleep(500);
}
}
}
創(chuàng)建線程的方式二
package com.thread;
/*
* 為了解決java是一個(gè)單繼承語(yǔ)言
* 如果繼承了線程類静浴,就不能繼承其他類反之亦然
*
* 所以建議使用第二種創(chuàng)建線程的方法:
* 讓自定義線程類【遵從】Runnable接口堰氓,實(shí)現(xiàn)Runnable接口中run方法,從而變成一個(gè)線程類
*
* 1苹享、自定義遵從Runnable接口的類
* 2双絮、實(shí)現(xiàn)run方法,在run方法中寫(xiě)線程代碼
* 3得问、創(chuàng)建線程類Thread對(duì)象囤攀,把Runnbale接口的實(shí)現(xiàn)類作為構(gòu)造方法的參數(shù)
* 4、利用Thread()的start方法
*
* 也可以簡(jiǎn)單的使用匿名內(nèi)部類
*/
class TestRunnable implements Runnable{
// 實(shí)現(xiàn)【遵從】Runnable接口之后宫纬,一定要實(shí)現(xiàn)的方法
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("當(dāng)前線程為:"+i+" "+Thread.currentThread());
}
}
}
public class Demo03 {
public static void main(String[] args) {
TestRunnable tr = new TestRunnable();
Thread thread = new Thread(tr);
thread.start();
/*
* 匿名內(nèi)部類的方法
* 利用匿名內(nèi)部類的匿名對(duì)象作為T(mén)hread類的構(gòu)造方法的參數(shù)焚挠,創(chuàng)建Thread類的匿名對(duì)象,直接調(diào)用start方法
*/
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("匿名內(nèi)部類作為方法的參數(shù):"+i);
}
}
}).start();
}
}
package com.thread;
/*
* 售票問(wèn)題
*
* 賣(mài)出票后漓骚,還沒(méi)有執(zhí)行到 ticket--語(yǔ)句蝌衔,會(huì)被其他線程搶去CPU執(zhí)行權(quán)
* 避免資源搶占----上鎖
* 【Java線程同步機(jī)制】
* 同步代碼塊:
* 格式:
* synchronized(鎖對(duì)象){
* 加鎖代碼榛泛。有且只有一個(gè)線程能進(jìn)入執(zhí)行,直到線程執(zhí)行完畢
* }
*注意事項(xiàng):
* 1噩斟、鎖對(duì)象可以是任意類型曹锨,但是只能是同一個(gè)對(duì)象,不能new對(duì)象剃允,每次執(zhí)行都是不同對(duì)象
* 2沛简、sleep()不會(huì)釋放鎖對(duì)象,不會(huì)開(kāi)鎖
* 3斥废、使用同步代碼塊椒楣,必須是真正意義上的線程搶占系統(tǒng)共享資源,同步的代碼越少越好
*
*/
class SaleTicket extends Thread{
private static int ticket = 50;
public SaleTicket(String name){
super(name);
}
@Override
public void run() {
while(true){
synchronized ("鎖") {
if (ticket >0){
System.out.println(Thread.currentThread().getName()+"已售出"+ticket+"張電影票");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
System.out.println("售罄!!!");
break;
}
ticket--;
}
}
}
}
public class Demo04 {
public static void main(String[] args) {
SaleTicket s1 = new SaleTicket("淘票票");
SaleTicket s2 = new SaleTicket("貓眼");
SaleTicket s3 = new SaleTicket("糯米");
s1.start();
s2.start();
s3.start();
}
}
package com.thread;
/**
* 死鎖
* 1牡肉、 存在兩個(gè)或者兩個(gè)以上的線程
* 2撒顿、存在兩個(gè)或者靈感以上的共享資源給這些線程使用
* @author Administrator
*
*/
class DeadLock implements Runnable{
@Override
public void run() {
if(Thread.currentThread().getName().equals("小明")){
synchronized ("電池") {
System.out.println("小明拿到電池,想要遙控器");
synchronized ("遙控器") {
System.out.println("小明拿到了遙控器荚板,開(kāi)啟了電視");
}
}
}else if(Thread.currentThread().getName().equals("小紅")){
synchronized ("遙控器") {
System.out.println("我有遙控器凤壁,給我電池");
synchronized ("電池") {
System.out.println("小紅拿到了電池,開(kāi)啟了電視");
}
}
}
}
}
public class Demo05 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Thread t1 = new Thread(new DeadLock(),"小明");
Thread t2 = new Thread(new DeadLock(),"小紅");
t1.start();
t2.start();
}
}
package com.thread;
/**
* 守護(hù)線程(后臺(tái)線程)
*
* 例如:
* 軟件的自動(dòng)更新跪另,軟件的日志拧抖,軟件的監(jiān)聽(tīng)
*
* 特征:
* 一旦整個(gè)程序運(yùn)行結(jié)束,只剩下守護(hù)線程免绿,這個(gè)時(shí)候守護(hù)線程也會(huì)跟著銷毀唧席,因?yàn)闆](méi)有意義
*
* Java了垃圾回收機(jī)制是守護(hù)線程還是普通線程
* 守護(hù)線程!嘲驾!
*/
public class Demo06 extends Thread{
public Demo06(String name){
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("軟件下載更新中...."+i+"%");
if(i == 100){
System.out.println("下載完成淌哟,是否安裝");
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
Demo06 d = new Demo06("守護(hù)線程");
// 設(shè)置為守護(hù)線程
d.setDaemon(true);
d.start();
for (int i = 0; i <= 50; i++) {
Thread.sleep(100);
System.out.println("主程序:"+i);
}
}
}