線程與進程
進程:正在運行的程序。
線程:一個進程的執(zhí)行單元阔籽。一條執(zhí)行流程流妻。
多線程:一個進程中有多條執(zhí)行路徑。
- 進程(Process)
狹義定義:進程是正在運行的程序的實例
廣義定義:進程是一個具有一定獨立功能的程序關(guān)于某個數(shù)據(jù)集合的一次運行活動笆制。它是操作系統(tǒng)動態(tài)執(zhí)行的基本單元绅这,在傳統(tǒng)的操作系統(tǒng)中,進程既是基本的分配單元在辆,也是基本的執(zhí)行單元证薇。
多進程可以提高CPU的使用率 - 線程(Thread)
線程是程序中一個單一的順序控制流程。進程內(nèi)的執(zhí)行單元匆篓,是CPU的基本單位浑度。 - 多線程
在單個程序中同時運行多個線程完成不同的工作,稱為多線程鸦概。
作用:
為了提高效率才使用箩张。
什么時候使用?
只有當要操作的代碼的內(nèi)容比較多(耗時),循環(huán)次數(shù)較多這樣的情況才使用。
多線程的生命周期
多線程的實現(xiàn)方式
Java是不能直接調(diào)用系統(tǒng)功能的窗市,所以先慷,我們沒辦法直接實現(xiàn)多線程程序。
所以Java可以去調(diào)用C/C++寫好的程序來實現(xiàn)程序的多線程咨察。由C/C++去調(diào)用系統(tǒng)功
能創(chuàng)建進程论熙,然后Java去調(diào)用,然后提供一些類供我們使用摄狱,我們就可以實現(xiàn)多線程了
Java提供的是Thread類赴肚,通過API知道其有2種方法實現(xiàn)多線程
(創(chuàng)建新執(zhí)行線程有兩種方法素跺。一種方法是將類聲明為 Thread 的子類。
該子類應(yīng)重寫 Thread 類的 run 方法誉券。接下來可以分配并啟動該子類的實例)
Thread類的方法:
void setName(String name)
-- 設(shè)置線程的名稱
String getName()
-- 獲取線程的名稱
static Thread currentThread()
-- 獲取當前正在運行的線程對象
方式1:繼承Thread類的方式
步驟 :
A:自定義類繼承Thread類
B:自定義類中重寫run()方法
為什么是run()方法呢?
C:創(chuàng)建對象
D:啟動線程
注意:
- 為什么是run()方法呢刊愚?
不是類中所有的代碼都需要被線程執(zhí)行的踊跟。
而這個時候,為了區(qū)分那些代碼能被線程執(zhí)行鸥诽,java提供了Thread類中的run()
用來包含那些被線程執(zhí)行的代碼商玫。 - run()和start()的區(qū)別?
- start():首先啟動了線程牡借,然后由jvm去調(diào)用該線程的run()方法
- run():僅僅是封裝線程的方法拳昌,直接調(diào)用是普通的方法
package com.lianwei.Thread.ExtendsThread;
package com.lianwei.Thread.ExtendsThread;
import com.sun.org.apache.xml.internal.resolver.helpers.PublicId;
public class MyThread extends Thread{
//構(gòu)造方法起名字
public MyThread(String name) {
super(name);
}
public MyThread() {
}
public void run(){
for (int x=1;x<=10;x++){
System.out.println(getName()+"=>"+x);
}
}
}
public class MyThreadDemo {
public static void main(String[] args){
//獲取main方法所在的線程對象的名稱,該腫么辦钠龙?
//public static Thread currentThread():返回當前在線的線程對象
System.out.println(Thread.currentThread().getName());
// 調(diào)用方法設(shè)置名稱
// //創(chuàng)建線程對象
// MyThread mt1 = new MyThread();
// MyThread mt2 = new MyThread();
// //設(shè)置線程名稱
// mt1.setName("康娜");
// mt2.setName("jyh");
// //啟動線程
// mt1.start();
// mt2.start();
// 帶參構(gòu)造方法給線程起名字
MyThread my1 = new MyThread("康娜");
MyThread my2 = new MyThread("jyh");
my1.start();
my2.start();
}
}
方式2:實現(xiàn)Runnable接口的方式
優(yōu)點:
1)可以避免單繼承的局限性炬藤。
2)只創(chuàng)建了一個資源對象。更好的實現(xiàn)了數(shù)據(jù)與操作的分離碴里。
(一般我們選擇第二種方式沈矿。)
package com.lianwei.Thread.ImpRunable;
import java.lang.Runnable;
public class ImplementsRunnable implements Runnable{
public void run(){
for (int x=0;x<10;x++){
//由于實現(xiàn)接口的方式不能直接使用Thread類的方法了,但可以間接使用
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
package com.lianwei.Thread.ImpRunable;
//步驟:
// A:創(chuàng)建一個類實現(xiàn)Runnable接口
// B:重寫run()方法
// C:創(chuàng)建類的對象
// D:把該對象作為Thread類的構(gòu)造參數(shù)傳遞咬腋。創(chuàng)建Thread類的對象羹膳,并執(zhí)行。
public class Runnable {
public static void main(String[] args){
ImplementsRunnable im = new ImplementsRunnable();
// D:把該對象作為Thread類的構(gòu)造參數(shù)傳遞根竿。創(chuàng)建Thread類的對象陵像,并執(zhí)行。
// Thread(Runnable target)
// Thread t1 = new Thread(im);
// Thread t2 = new Thread(im);
// t1.setName("康娜");
// t2.setName("jyh");
// Thread(Runnable target,String name)
Thread t1 =new Thread(im,"康娜");
Thread t2 =new Thread(im,"jyh");
t1.start();
t2.start();
}
}
線程優(yōu)先級
- 線程優(yōu)先級級別
線程默認優(yōu)先級是5寇壳。范圍是1-10
Thread.MAX_PRIORITY //10
Thread.MIN_PRIORITY //1
Thread.NORM_PRIORITY //5
- 方法
int getPriority()
-- 獲取線程優(yōu)先級醒颖。
void setPriority(int pri)
-- 設(shè)置線程的優(yōu)先級。 - 注意
較高的優(yōu)先級會給線程更多的執(zhí)行機會九巡,但不保證優(yōu)先級高的一定先執(zhí)行图贸。
優(yōu)先級可以在一定的程度上(即更大的概率)讓線程獲較多的執(zhí)行機會
線程調(diào)度(了解)
- 分時調(diào)度模型:所有線程輪流使用CPU的使用權(quán),平均分配每個線程的時間
- 搶占式調(diào)度模型:隨機分配使用權(quán)冕广,優(yōu)先級高的使用幾率大一點疏日。
線程控制
線程休眠
package com.lianwei.Thread.ControlThread;
import java.util.Date;
public class ThreadSleep extends Thread{
public void run(){
for (int x=1;x<=10;x++){
System.out.println(getName()+":"+x+"日期:"+new Date());
//睡眠1秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package com.lianwei.Thread.ControlThread;
import com.lianwei.Thread.ExtendsThread.MyThread;
public class ThreadSleepDemo {
public static void main(String[] args) {
//創(chuàng)建線程對象
ThreadSleep mt1 = new ThreadSleep();
ThreadSleep mt2 = new ThreadSleep();
//設(shè)置線程名稱
mt1.setName("康娜");
mt2.setName("jyh");
//啟動線程
mt1.start();
mt2.start();
}
}
線程加入
package com.lianwei.Thread.ControlThread;
import java.util.Date;
public class ThreadJoin extends Thread{
public void run(){
for (int x=1;x<=10;x++){
System.out.println(getName()+":"+x+"日期:"+new Date());
}
}
}
package com.lianwei.Thread.ControlThread;
public class ThreadJoinDemo {
public static void main(String[] args) {
//創(chuàng)建線程對象
ThreadJoin tj1 = new ThreadJoin();
ThreadJoin tj2 = new ThreadJoin();
ThreadJoin tj3 = new ThreadJoin();
tj1.setName("動物");
tj2.setName("貓");
tj3.setName("狗");
tj1.start();
try {
tj1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
tj2.start();
tj3.start();
}
}
線程禮讓
package com.lianwei.Thread.ControlThread;
import java.util.Date;
public class ThreadYield extends ThreadJoin{
public void run(){
for (int x=1;x<=10;x++){
System.out.println(getName()+":"+x+"日期:"+new Date());
Thread.yield();
}
}
}
package com.lianwei.Thread.ControlThread;
//public static void yield():暫停當前的線程,并執(zhí)行其他的線程
//它可以讓線程跟和諧撒汉,但還是不能保證一人一次
public class ThreadYieldDemo {
public static void main(String[] args){
ThreadYield ty1 = new ThreadYield();
ThreadYield ty2 = new ThreadYield();
ty1.setName("康娜");
ty2.setName("jyh");
}
}
后臺線程
package com.lianwei.Thread.ControlThread;
import java.util.Date;
public class ThreadDaemon extends ThreadJoin{
public void run(){
for (int x=1;x<=100;x++){
System.out.println(getName()+":"+x);
}
}
}
package com.lianwei.Thread.ControlThread;
//public final void setDaemon(boolean on):將該線程標記為守護線程或用戶線程
//當正在運行的線程都是守護線程時沟优,java虛擬機退出,該方法必須在啟動前調(diào)用
public class ThreadDaemonDemo {
public static void main(String[] args){
ThreadDaemon td1 = new ThreadDaemon();
ThreadDaemon td2 = new ThreadDaemon();
td1.setName("康娜");
td2.setName("雛鶴愛");
td1.setDaemon(true);
td2.setDaemon(true);
td1.start();
td2.start();
Thread.currentThread().setName("jyh");
for(int x =0;x<=5;x++){
System.out.println(Thread.currentThread().getName()+":"+x);
}
}
}
中斷線程
package com.lianwei.Thread.ControlThread;
import java.util.Date;
public class ThreadStop extends Thread{
public void run(){
System.out.println("開始執(zhí)行:"+new Date());
//我要休息10秒
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// e.printStackTrace();
System.out.println("線程被終止了");
}
System.out.println("結(jié)束執(zhí)行:"+ new Date());
}
}
package com.lianwei.Thread.ControlThread;
//public final void stop():讓線程停止睬辐,過時了挠阁,但還可以用
//public void interrupt():中斷線程宾肺。把線程的狀態(tài)終止,并拋出InterruptedException異常
public class ThreadStopDemo {
public static void main(String[] args){
ThreadStop ts = new ThreadStop();
ts.start();
//超過3秒不好侵俗,你就完了
try {
Thread.sleep(3000);
//ts.stop();
ts.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
鎖锨用,同步代碼塊,同步方法
同步機制(鎖機制)
同步代碼塊
格式:
synchronized(鎖對象){
需要同步的代碼
}
- 作用:
保證在某一時刻只會有一個線程在執(zhí)行同步代碼塊中的代碼 - 鎖對象:
可以是任意對象隘谣,但是操作相同資源的鎖對象必須是同一個增拥。 - 解釋:
線程只有拿到了鎖對象,才能執(zhí)行同步代碼塊中的代碼寻歧。換言之掌栅,這里的代碼如果執(zhí)行了,說明該線程拿到了鎖對象码泛,其他線程就不能拿到該鎖對象猾封。
同步方法
- 同步方法:
加了synchronized關(guān)鍵字修飾的方法。 - 鎖對象:
非靜態(tài)方法的鎖對象是:this對象噪珊。
靜態(tài)方法的鎖對象是:當前類的字節(jié)碼文件對象晌缘。(類名.class)
public synchronized void show(){}
public static synchronized void show(){} - 什么時候用
什么時候用同步代碼塊,什么時候用同步方法卿城?
盡可能用同步代碼塊(被同步的內(nèi)容越少越好)
如果一個方法內(nèi)的所有代碼都被同步代碼塊包住了枚钓,那就用同步方法就可以了
同步的好處及弊端
- 好處:解決了多線程的安全問題
- 弊端:因為每個線程去判斷同步上的鎖,這降低程序的運行效率會
死鎖
死鎖原因總結(jié)
線程1自身拿著一個鎖:A鎖瑟押,線程2自身拿著一個鎖:B鎖
當線程1要用B鎖搀捷,線程B要用A鎖的時候就會發(fā)生死鎖