1. 程式人生 > >【Java系列】【基礎版】多線程基礎

【Java系列】【基礎版】多線程基礎

java

  1. 多線程基礎

1.1 認識進程和線程

1.1.1 什麽是進程

1.1.1.1 進程是正在進項的程序,是資源分配的一個基本單位,有內存分配;

1.1.2 什麽是線程

1.1.2.1 線程是進程的一個執行單位,也是進程的執行順序;

1.1.2.2 一個進程至少有一個線程,可以由兩個或以上的線程;

1.1.3 JVM至少有幾個線程

1.1.3.1 至少有一個或兩個線程,main方法和垃圾回收線程;

1.1.4 什麽是多線程

1.1.4.1 2個或以上的線程去執行

1.1.5 多線程的作用

1.1.5.1 提高效率,線程之間切換的小號是可以接受的;

1.1.5.2 單線程容易阻塞;

1.1.5.3 多個線程同時執行代碼;

1.1.5.4 一個線程掛了,還有其他的線程在,程序還在執行

1.1.6 進程和線程是誰創建的

都是操作系統創建的

1.1.7 如何自定義一個線程

1.1.7.1 繼承Thread類,重寫run方法

1.1.7.2 生成對象

1.1.7.3 開啟start

1.1.8 所有實現的接口

1.1.8.1 Runnable接口

1.1.8.2 new線程對象的時候,創建了線程

1.1.8.3 start方法,溝通了操作系統,告訴操作系統有一個線程要開啟,也調用了run


1.2 代碼示例

1.2.1 在main主線程裏,再度開啟其他線程

1.2.1.1 測試類:

public class Test {

public static void main(String[] args) throws ParseException {

Test001 t = new Test001();//這裏代表著產生了一個線程

Test001 t1 = new Test001();//這裏代表著產生了一個線程

System.out.println("開啟線程之前");

//t1.run();//代表著調用了對象的方法

t.start();//這裏代表開啟了一個線程,是溝通了操作系統

t1.start();//這裏代表開啟了一個線程,是溝通了操作系統

try {

Thread.sleep(15);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("開啟線程之後");

System.out.println("main over");

}

}

1.2.1.2 重寫run方法類,繼承Thread類:

class Test001 extends Thread{

@Override

public void run() {

for (int i = 0; i < 100; i++) {

try {

sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("run .. "+i);

}

}

}



1.2.2 創建一個線程,和主程序交替執行

1.2.2.1 測試類

public class ThreadTest {

public static void main(String[] args) {

Test t = new Test();

t.start();

for (int i = 0; i < 10; i++) {

System.out.println("main>>>"+i);

}

System.out.println("main - gg");

}

}

1.2.2.2 方法類

class Test extends Thread{

int i = 0;

@Override

public void run() {

while(true){

if(i<10){

System.out.println("run方法..." + i++);

}else{

System.out.println("run - OVER");

break;

}

}

}

}


1.2.3 模擬買票功能

1.2.3.1 測試類

public class TestRunnable01 {

public static void main(String[] args) {

Runnable x1 = new XinXiaoMi();

Thread t1 = new Thread(x1);

Thread t2 = new Thread(x1);

Thread t3 = new Thread(x1);

t1.setName("小紅");

t2.setName("小藍");

t3.setName("小綠");

t1.start();

t2.start();

t3.start();

}

}

1.2.3.2 方法類

class XinXiaoMi implements Runnable{

static int i =100;//共享的

Object o = new Object();

@Override

public void run() {

boolean b = true;

while(b){

synchronized (o) {

if(i>0){//i = 1

try {

Thread.sleep(10);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+"...賣出了手機,編號是..." + i--);

}

else{

break;

}

}

}

}

}


1.2.4 小明和老婆同時存錢,每次存取500元,每人存5次

1.2.4.1 測試類:

public class TestRunnable02 {

public static void main(String[] args) {

test t = new test();

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

t1.setName("小明");

t2.setName("陳學冬");

t1.start();

t2.start();

}

}

1.2.4.2 方法類:

class test implements Runnable{

int con = 0;//初始定義了賬戶余額為0元

Object o = new Object();

@Override

public void run() {

synchronized (o) {

for (int i = 0; i < 5; i++) {

con += 500;

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+" 存了500大洋---此時賬戶余額為 。。"+con);

}

}

}

}


1.2.4 小明和老婆同時存錢,每次存取500元,每人存5次; 同時實現方法的同步

1.2.4.1 測試類

public class TestM {

public static void main(String[] args) {

test00 t = new test00();

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

t1.setName("小明");

t2.setName("baby");

t2.start();

t1.start();

}

}

1.2.4.2 方法類

class test00 implements Runnable{

int con = 0;//初始定義了賬戶余額為0元

Object o = new Object();

@Override

public void run() {

System.out.println(Thread.currentThread().getName()+" 到達房間門口");

this.show();//一次就好,許你地老天荒

}

public synchronized void show(){

System.out.println(Thread.currentThread().getName()+" 鎖住了房間");

for (int i = 0; i < 5; i++) {

con += 500;

try {

Thread.sleep(10);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName()+" 存入了500,此時余額是 "+con);

}

System.out.println(Thread.currentThread().getName()+" 離開了房間,打開了鎖");

}

}


1.2.5 小明和老婆同時存錢,每次存取500元,每人存5次; 同時實現方法的同步;同時實現交替存儲

1.2.5.1 測試類

public class TestM2 {

public static void main(String[] args) {

test000 t = new test000();

Thread t1 = new Thread(t);

Thread t2 = new Thread(t);

t1.setName("小明");

t2.setName("baby");

t2.start();

t1.start();

}

}

1.2.5.2 方法類

class test000 implements Runnable{

int con = 0;//初始定義了賬戶余額為0元

Object o = new Object();

@Override

public void run() {

for (int i = 0; i < 5; i++) {

//等待區

show();

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

public synchronized void show(){

System.out.println(Thread.currentThread().getName()+" 上鎖了");

con += 500;

System.out.println(Thread.currentThread().getName()+" 存入了 500 , 此時余額為 "+con);

System.out.println(Thread.currentThread().getName()+" 鎖開了");

}

}


1.2.6 死鎖的示例

1.2.6.1 測試類:

/* Runnablere =new Runnable() {

public void run() {

}

};

*/

public class Test01 {

public static void main(String[] args) {

TestSY ts1 = new TestSY();

Thread th1 = new Thread(ts1);

Thread th2= new Thread(ts1);

th1.start();

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

TestSY.b = false;

th2.start();

}

}


1.2.6.2 方法類:


class TestSY implements Runnable{

static boolean b = true;

Object o = new Object();

Object o1 = new Object();

@Override

public void run() {

if( b ){

synchronized (o) {

System.out.println("if 拿到了 o 的鎖");

try {

Thread.sleep(10000);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (o1) {

System.out.println("if-----");

}

}

}else{

synchronized (o1) {

System.out.println("else 拿到了 o1 的鎖");

try {

Thread.sleep(10000);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (o) {

System.out.println("else-----");

}

}

}

}

}


1.3 cpu調度

cpu的時間片,cpu控制著執行;

cpu會自行分配資源給線程,得到資源的線程可以執行,沒有得到資源的線程沒有辦法執行;

多個cpu才是真正意義上的同時執行多線程,因為運行速度特別多,會給我們產生錯覺,認為是同時執行的;


1.4 線程的狀態

1.4.1 新生

1.4.1.1 new對象的時候代表著新生;

1.4.2 就緒

1.4.2.1 start方法代表著就緒,這個時候在等待著CPU的資源;如果有資源就進入執行狀態,沒有資源就繼續等待;

1.4.3 執行

1.4.3.1 拿到時間片,正在執行;時間片被拿走了就離開了執行狀態;

1.4.4 阻塞

1.4.4.1 睡覺sleep,讓資源;時間結束了就回到就緒狀態,等待資源;

1.4.5 死亡

1.4.5.1 線程執行結束;非正常死亡方式;


1.5 兩種創建線程方式的比較

1.5.1 繼承方式創建簡單,使用的方法也多;

1.5.2 java是單繼承的,使用集成方式過於死板;

1.5.3 繼承是不共享資源的,實現方式是共享的;

1.5.4 主要由於單繼承的機制,推薦使用Runnable接口實現這種方式

1.5.4.1 實現接口,重寫方法

1.5.4.2 new一個對象

1.5.4.3 把new的對象放進線程(Thread)對象裏

1.5.4.4 用線程對象開啟線程

1.5.4.5 註意:run方法不能拋異常


1.6 同步代碼塊原理解析

1.6.1 java提供了鎖的機制synchronized ,可以鎖住一段代碼,在任何時期這段代碼裏面最多只有一個線程在執行。每個要進來的線程都會先判斷此處有沒有上鎖。

1.6.1.1 如果沒有,就進去並且上鎖,再執行完之後才會離開,同時打開鎖,其他的線程才可以進來

1.6.1.2 如果被鎖,再門口等待,進不去; 這裏鎖,鎖的是對象。具體鎖那個對象呢。具體情況具體分析

1.6.2 同步的優缺點

1.6.2.1 同步的前提

1.6.2.1.1 兩個或兩個以上的線程去操作共享數據時

1.6.2.2 同步的好處

1.6.2.2.1 保證了線程的安全性

1.6.2.3 同步的缺陷

1.6.2.3.1 消耗增加,但是影響不大

1.6.2.3.2 使用不當容易造成死鎖








































【Java系列】【基礎版】多線程基礎