**面试题:程序,进程与线程的区别**
程序:程序(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()的对象必须是加锁的
***
![](https://box.kancloud.cn/563b0f371922ee444092ad9853318fa1_924x654.png)
~~~
/**
* 杯子类
* 充当生产者消费者模型中的共享资源
* @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();
}
}
~~~
***
### 线程的生命周期
![](https://box.kancloud.cn/835a14340eacb5847143b7560178ae42_714x561.png)
#### 作业:一个服务器,多个客户端传输二进制文件
~~~
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();
}
}
}
}
~~~