@[TOC](多線程與高并發(fā))
# 認(rèn)識(shí)并發(fā)與并行
并發(fā)是針對(duì)一個(gè)CPU來講,“同一時(shí)間”執(zhí)行多個(gè)任務(wù)--實(shí)質(zhì)上是劃分時(shí)間片,由于時(shí)間很短給人的感覺是是同時(shí)執(zhí)行的;
并行是針對(duì)多個(gè)CPU來講的,同時(shí)執(zhí)行多個(gè)任務(wù)(一個(gè)CPU執(zhí)行一個(gè)),這是真正意義上的同時(shí)執(zhí)行;
## 入門程序分析(打印---HelloWorld)
```java
class Car{
? ? public void drive(){
? ? ? ? System.out.println("我會(huì)跑");
? ? }
}
public class HuiXinThread {
? ? public static void main(String[] args) {
? ? ? ? Car car=null;
? ? ? ? System.out.println("HelloWorld");//主線程---main()
? ? ? ? car.drive();//異常處理的線程---
? ? ? ? new Car().drive();//運(yùn)行完畢,new Car()匿名對(duì)象會(huì)被回收--垃圾收集器
? ? }
}
```
所以在我們初學(xué)java時(shí),并非只有一個(gè)線程,其實(shí)是多線程的包括? 主線程、處理異常的線程,以及垃圾收集器線程等等;
### 線程之間是如何搶占CPU資源的?
先來看一個(gè)案例----
當(dāng)我們打開一個(gè)程序前,其實(shí)就是存放在電腦中的代碼(靜態(tài)的),打開之后,這個(gè)程序才算開啟,(為他分配空間以及CPU資源),然后在這個(gè)程序中開啟不同的功能--即開啟了多個(gè)線程,然后CPU再次為這些線程服務(wù),如果線程過多,CPU不夠用,那就會(huì)使得一個(gè)CPU要執(zhí)行多個(gè)線程---形成了并發(fā)(采用時(shí)間片機(jī)制),同時(shí)可以為線程設(shè)置優(yōu)先級(jí)來提高相應(yīng)線程被先執(zhí)行的概率(并不是優(yōu)先級(jí)低就一定會(huì)被后執(zhí)行)
### 自定義線程的執(zhí)行
線程的創(chuàng)建方式---
第一種---繼承Thread類
```java
class Car extends? Thread{
? ? @Override
? ? public void run(){
? ? ? ? for (int i=0;i<10;i++){
? ? ? ? System.out.println("我會(huì)跑");}
? ? }
}
public class HuiXinThread {
? ? public static void main(String[] args) {
? ? ? ? //主線程---main()
? ? ? ? for (int i = 0; i <10 ; i++) {
? ? ? ? ? ? System.out.println("HelloWorld"+i);
? ? ? ? }
? ? new Car().run();
? ? }
}
```
這一種并不是多線程,因?yàn)樵摲绞街皇前裷un()當(dāng)成一個(gè)普通方法來執(zhí)行的;,所以運(yùn)行結(jié)果是 先執(zhí)行main--主線程,然后執(zhí)行run(),此時(shí)run也是屬于主線程里面的;

```java
class Car extends? Thread{
? ? @Override
? ? public void run(){
? ? ? ? for (int i=0;i<10;i++){
? ? ? ? System.out.println("我會(huì)跑");}
? ? }
}
public class HuiXinThread {
? ? public static void main(String[] args) {
? ? ? ? //主線程---main()
? ? ? ? for (int i = 0; i <10 ; i++) {
? ? ? ? ? ? System.out.println("HelloWorld"+i);
? ? ? ? }
? ? new Car().start();
? ? }
}
```
start()是父類的方法,但是與逆行結(jié)果依然跟上面一樣---
原因是我們在主線程(for循環(huán))執(zhí)行時(shí)并沒有子線程參與進(jìn)來,要想實(shí)現(xiàn)并發(fā)效果需要調(diào)整一下start()方法的位置--
```java
class Car extends? Thread{
? ? @Override
? ? public void run(){
? ? ? ? for (int i=0;i<10;i++){
? ? ? ? System.out.println("我會(huì)跑"+i);}
? ? }
}
public class HuiXinThread {
? ? public static void main(String[] args) {
? ? ? ? //子線程
? ? ? ? new Car().start();
? ? ? ? //主線程---main()
? ? ? ? for (int i = 0; i <10 ; i++) {
? ? ? ? ? ? System.out.println("HelloWorld"+i);
? ? ? ? }
? ? }
}
```

> 運(yùn)行后發(fā)現(xiàn)---有時(shí)候并不一定會(huì)出現(xiàn)并發(fā)---當(dāng)運(yùn)行量少的時(shí)候;
# 為線程設(shè)置名字和獲取線程名字
```java
public class Car extends? Thread{
? ? @Override
? ? public void run(){
? ? ? ? for (int i=0;i<10;i++){
? ? ? ? ? ? System.out.println(this.getName()+i);}
? ? }
}
public class HuiXinThread {
? ? public static void main(String[] args) {
? ? ? ? //子線程
? ? ? ? ? ? Car car= new Car();
? ? ? ? ? ? car.setName("小汽車");
? ? ? ? car.start();
? ? ? ? //主線程---main()
? ? ? ? for (int i = 0; i <10 ; i++) {
? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+i);
? ? ? ? }
? ? }
}
```

還可以通過構(gòu)造器來設(shè)置線程名字---
```java
public class Car extends? Thread{
? ? public Car(String name){
? ? ? ? super(name);
? ? }
? ? @Override
? ? public void run(){
? ? ? ? for (int i=0;i<10;i++){
? ? ? ? ? ? System.out.println(this.getName()+i);}
? ? }
}
public class HuiXinThread {
? ? public static void main(String[] args) {
? ? ? ? //子線程
? ? ? ? ? ? Car car= new Car("小火車");
? ? ? ? ? ? //car.setName("小汽車");
? ? ? ? car.start();
? ? ? ? //主線程---main()
? ? ? ? for (int i = 0; i <10 ; i++) {
? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+i);
? ? ? ? }
? ? }
}
```

設(shè)置線程名的父類構(gòu)造方法---

# 線程開啟的方式---
## 繼承Thread類--
演示代碼如上,不在贅述----注意點(diǎn)為? 開啟線程是start()方法,而run()方法還是當(dāng)作一個(gè)普通方法來處理的;
start()源碼---
> 此方法不為主方法線程或“系統(tǒng)”調(diào)用。?
> 虛擬機(jī)創(chuàng)建/設(shè)置的組線程。 添加的新功能?
> 到這個(gè)方法以后可能還需要添加到VM中。

## 實(shí)現(xiàn)Runable接口
```java
class BuyBook implements Runnable{
? ? @Override
? ? public void run() {
? ? ? ? for (int i = 0; i < 10; i++) {
? ? ? ? ? ? System.out.println("i---"+Thread.currentThread());
? ? ? ? }
? ? }
}
public class Test {
? ? public static void main(String[] args)? {
? ? ? ? BuyBook bb= new BuyBook();
? ? ? ? bb.run();
? ? ? ? for (int i = 0; i <10 ; i++) {
? ? ? ? ? ? System.out.println("i---"+Thread.currentThread());
? ? ? ? }
? ? }
}
```

> Runnable接口中只有一個(gè)run方法,

并沒有發(fā)現(xiàn)start方法,需要怎么做呢?
start()方法在Thread類中,所以要先在創(chuàng)建一個(gè)Thread的對(duì)象
```java
class BuyBook implements Runnable{
? ? @Override
? ? public void run() {
? ? ? ? for (int i = 0; i < 3; i++) {
? ? ? ? ? ? System.out.println("i---"+Thread.currentThread());
? ? ? ? }
? ? }
}
public class Test {
? ? public static void main(String[] args)? {
? ? ? ? Thread.currentThread().setName("主線程");
? ? ? ? BuyBook bb= new BuyBook();
? ? ? ? Thread thread= new Thread(bb);
? ? ? ? thread.setName("子線程");
? ? ? ? thread.start();
? ? ? ? for (int i = 0; i <3 ; i++) {
? ? ? ? ? ? System.out.println("i---"+Thread.currentThread());
? ? ? ? }
? ? }
}
```
> public Thread(Runnable target) {//構(gòu)造器--傳入的是Runnable對(duì)象
? ? ? ? this(null, target, "Thread-" + nextThreadNum(), 0);
? ? }
當(dāng)處理量少的時(shí)候得到的結(jié)果像是順序執(zhí)行的,多運(yùn)行幾次就可以了;
