多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
**面试题:程序,进程与线程的区别** 程序:程序(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(); } } } } ~~~