**面試題:程序,進程與線程的區別**
程序:程序(program)只是一組指令的有序集合,是永存的。
進程:在計算機上正在運行的程序(計算機上并發執行的任務)
線程:進程中的小進程,占用資源較小,也就是說,線程存在于進程之中
引入線程的好處
(1)易于調度。
(2)提高并發性。通過線程可方便有效地實現并發性。進程可創建多個線程來執行同一程序的不同部分。
(3)開銷少。創建線程比創建進程要快,所需開銷很少。
#### 進程與線程區別與聯系
(1)一個線程只能屬于一個進程,而一個進程可以有多個線程,但至少有一個線程。
(2)資源分配給進程,同一進程的所有線程共享該進程的所有資源。
(3)處理機分給線程,即真正在處理機上運行的是線程。
(4)線程在執行過程中,需要協作同步。不同進程的線程間要利用消息通信的辦法實現同步。
(5)劃分尺度:線程更小,所以多線程程序并發性更高;
(6)資源分配:進程是資源分配的基本單位,同一進程內多個線程共享其資源;
(7)地址空間:進程擁有獨立的地址空間,同一進程內多個線程共享其資源;
(8)處理器調度:線程是處理器調度的基本單位;
(9)執行:每個線程都有一個程序運行的入口,順序執行序列和程序的出口,但線程不能單獨執行,必須組成進程,一個進程至少有一個主線程。簡而言之,一個程序至少有一個進程,一個進程至少有一個線程。
***
### 如何創建一個線程
線程就是一個普通類,只不過這個類需要繼承**Thread**類或者實現**Runnable**接口
重寫run方法,實現線程功能
**如何啟動一個線程**
**①如果是線程類繼承Thread,啟動線程不能直接調用run(),而是調用start()啟動線程**
~~~
public class ThreadDemo1 extends Thread{
// run方法是專門寫線程功能的方法
@Override
public void run() {
for(int i = 50;i < 101;i++){
System.out.println(i);
}
}
}
~~~
~~~
public class ThreadTest {
public static void main(String[] args) {
ThreadDemo1 td1 = new ThreadDemo1();
// 啟動線程
td1.start();
for(int i = 0;i < 50;i++) {
System.out.println(i);
}
}
}
~~~
***
**面試題:start()與run()的區別**
run()是寫線程功能的方法
start()是啟動線程的方法
***
線程一旦啟動,線程間完全平等,先運行誰完全取決于誰競爭到CPU資源,main方法本身就是一個線程,線程是運行程序的最小單位
**②如果線程類是實現了Runnable接口,啟動線程需要借助Thread類對象,依舊調用start()**
~~~
public class ThreadDemo2 implements Runnable{
@Override
public void run() {
for(int i = 50;i < 101;i++){
System.out.println(i);
}
}
}
~~~
啟動線程時,Runnable接口接口中沒有提供啟動線程的方法,所以啟動線程時,依舊需要Thread對象幫助啟動
~~~
public class ThreadTest {
public static void main(String[] args) {
ThreadDemo2 td2 = new ThreadDemo2();
Thread td = new Thread(td2);
// 啟動線程
td.start();
for(int i = 0;i < 50;i++) {
System.out.println(i);
}
}
}
~~~
***
### 數據同步問題(線程安全問題)
數據同步問題:發生在多線程操作共享資源時
線程間的關系
①解決數據同步:互斥(鎖機制,關鍵字synchronized)
同步方法:簡單,性能低下
~~~
public class TranStation {
// 票的數量
int ticketNum = 10;
// 賣票
public synchronized int saleTicket() {
if(ticketNum > 0) {
ticketNum--;
// 休眠--模擬延遲
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
return ticketNum+1;
}
return 0;
}
}
~~~
同步塊:只對需要的代碼加鎖,性能好,但是需要判斷上鎖的代碼及對象
~~~
public int saleTicket() {
if(ticketNum > 0) {
synchronized(this) {
ticketNum--;
// 休眠--模擬延遲
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
return ticketNum+1;
}
}
return 0;
}
~~~
***
火車站代售點售票
~~~
public class TranStation {
// 票的數量
int ticketNum = 10;
// 賣票
public int saleTicket() {
if(ticketNum > 0) {
synchronized(this) {
ticketNum--;
// 休眠--模擬延遲
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
return ticketNum+1;
}
}
return 0;
}
}
~~~
~~~
public class HuangGuProxy implements Runnable{
TranStation ts;
public HuangGuProxy(TranStation ts) {
super();
this.ts = ts;
}
@Override
public void run() {
while(true) {
int num = ts.saleTicket();
if(num > 0) {
System.out.println("皇姑代售點售出"+num+"號票");
}else {
return;
}
}
}
}
~~~
~~~
public class HunNanProxy implements Runnable{
TranStation ts;
public HunNanProxy(TranStation ts) {
super();
this.ts = ts;
}
@Override
public void run() {
while(true) {
int num = ts.saleTicket();
if(num > 0) {
System.out.println("渾南代售點售出"+num+"號票");
}else {
return;
}
}
}
}
~~~
~~~
public class ShenBeiProxy implements Runnable{
TranStation ts;
public ShenBeiProxy(TranStation ts) {
super();
this.ts = ts;
}
@Override
public void run() {
while(true) {
int num = ts.saleTicket();
if(num > 0) {
System.out.println("沈北代售點售出"+num+"號票");
}else {
return;
}
}
}
}
~~~
~~~
public class Test {
public static void main(String[] args) {
TranStation ts = new TranStation();
ShenBeiProxy sbp = new ShenBeiProxy(ts);
HunNanProxy hnp = new HunNanProxy(ts);
HuangGuProxy hgp = new HuangGuProxy(ts);
Thread t1 = new Thread(sbp);
Thread t2 = new Thread(hnp);
Thread t3 = new Thread(hgp);
t1.start();
t2.start();
t3.start();
}
}
~~~
***
②協作--生產者消費者模型
生產者消費者模型:產品被生產之前,消費者不能消費,產品被被消費之前,生產者不能生產--共享資源就是產品
***
**面試題:sleep()和wait()的區別?**
sleep()是Thread類的靜態方法
wait()是Object類的方法
sleep()需要傳參,代表毫秒數,休眠的時間一旦到達,線程自動被喚醒
wait()不要傳參,線程不會自動喚醒,只能手動喚醒
調用wait()的對象必須是加鎖的
***

~~~
/**
* 杯子類
* 充當生產者消費者模型中的共享資源
* @author Administrator
*
*/
public class Cup {
boolean isEmpty = true;// true代表空,false代表滿
}
~~~
~~~
/**
* 生產者
* @author Administrator
*
*/
public class Productor implements Runnable{
String name;
Cup cup;
public Productor(Cup cup,String name) {
super();
this.cup = cup;
this.name = name;
}
@Override
public void run() {
while(true) {
// 共享資源加鎖
synchronized (cup) {
if(cup.isEmpty) {
// 續杯
cup.isEmpty = false;
System.out.println(name+"將咖啡杯續的滿滿的");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 喚醒所有等待隊列當中的線程
cup.notifyAll();
}else {
try {
cup.wait();// 為什么是cup?將當前線程放進cup的等待隊列,wait方法的調用者必須加鎖
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
~~~
~~~
/**
* 消費者
* @author Administrator
*
*/
public class Customer implements Runnable{
Cup cup;
String name;
public Customer(Cup cup,String name) {
super();
this.cup = cup;
this.name = name;
}
@Override
public void run() {
while(true) {
// 共享資源加鎖
synchronized (cup) {
if(!cup.isEmpty) {
// 續杯
cup.isEmpty = true;
System.out.println(name+"將咖啡一口干了");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 喚醒所有等待隊列當中的線程
cup.notifyAll();
}else {
try {
cup.wait();// 為什么是cup?將當前線程放進cup的等待隊列,wait方法的調用者必須加鎖
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
~~~
~~~
public class Test {
public static void main(String[] args) {
Cup cup = new Cup();
// 生產者
Productor p1 = new Productor(cup, "楊英");
Productor p2 = new Productor(cup, "王歡");
// 消費者
Customer c1 = new Customer(cup, "陳闖");
Customer c2 = new Customer(cup, "張秋");
Customer c3 = new Customer(cup, "高昂");
Thread tp1 = new Thread(p1);
Thread tp2 = new Thread(p2);
Thread tc1 = new Thread(c1);
Thread tc2 = new Thread(c2);
Thread tc3 = new Thread(c3);
tp1.start();
tp2.start();
tc1.start();
tc2.start();
tc3.start();
}
}
~~~
***
### 線程的生命周期

#### 作業:一個服務器,多個客戶端傳輸二進制文件
~~~
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class BinaryFileTransferServer {
public static void main(String[] args) {
Socket socket = null;
ServerSocket ss;
try {
ss = new ServerSocket(9528);
while(true) {
socket = ss.accept();
System.out.println(socket.getInetAddress()+"發起鏈接...");
// 開啟一個傳輸數據的線程
TransferThread tt = new TransferThread(socket);
Thread t1 = new Thread(tt);
t1.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
~~~
~~~
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class TransferThread implements Runnable{
Socket socket;
public TransferThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
FileInputStream fis = null;
BufferedInputStream in = null;
OutputStream os = null;
BufferedOutputStream out = null;
try {
fis = new FileInputStream("D:/source.wmv");
in = new BufferedInputStream(fis);
os = socket.getOutputStream();
out = new BufferedOutputStream(os);
byte buffer[] = new byte[1024];
int len = in.read(buffer);
while(len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
System.out.println("向客戶端傳輸完畢...");
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
~~~
~~~
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
public class BinaryFileTransferClient {
public static void main(String[] args) {
Socket socket = null;
InputStream is = null;
BufferedInputStream in = null;
FileOutputStream fos = null;
BufferedOutputStream out = null;
try {
socket = new Socket("10.25.41.46", 9528);
is = socket.getInputStream();
in = new BufferedInputStream(is);
fos = new FileOutputStream("E:/dest.wmv");
out = new BufferedOutputStream(fos);
byte buffer[] = new byte[1024];
int len = in.read(buffer);
while(len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
System.out.println("文件下載完畢...");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
~~~