黑马程序员Java零基础视频教程_下部(P135-P200)学习笔记
1 多线程
1.1 什么是多线程?
- 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
- 进程:进程是程序的基本执行实体



多线程就是可以同时干多件事情,把等待的时间充分利用起来
多线程——提高程序的运行效率
多线程的应用场景
- 软件中的耗时操作——拷贝、迁移大文件、加载大量的资源文件
- 所有的聊天软件
- 所有的后台服务器
1.2 多线程的并发与并行
并发:在同一时刻,有多个指令在单个CPU上交替执行

并行:在同一时刻,有多个指令在多个CPU上同时执行

但是电脑没有多个CPU啊?

以2核4线程为例:

1.3 多线程的实现方式
多线程的实现方式
①继承Thread类的方式进行实现
②实现Runnable接口的方式进行实现
③利用Callable接口和Future接口方式实现
1.3.1 继承Thread类的方式进行实现
创建新执行线程有两种方法。一种方法是将类声明为Thread 的子类。该子类应重写Thread 类的run 方法。接下来可以分配并启动该子类的实例。
例如,计算大于某一规定值的质数的线程可以写成:
1 2 3 4 5 6 7 8 9
| class PrimeThread extends Thread { PrimeThread(long minPrime) { this. minPrime = minPrime; } public void run() { } } Lobster AIjava运行12345678
|
然后,下列代码会创建并启动一个线程:
1 2 3
| PrimeThread p = new Prime Ihread(143); p. start(); Lobster AIjava运行12
|
MyThread.java
1 2 3 4 5 6 7 8 9 10
| public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("HelloWorld"); } } }
Lobster AIjava运行123456789
|
Main.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import java.lang.String;
public class main {
public static void main(String[] args){
MyThread t1 = new MyThread(); t1.start();
}
}
Lobster AIjava运行123456789101112131415161718
|
但是目前上面只运行了单个线程,所以与之前学的差不多,唯一区别就是我把函数方法换成了start
下面我们建立2个线程看一下结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName()+"HelloWorld"); } } }
Lobster AIjava运行123456789 import java.lang.String;
public class main {
public static void main(String[] args){
MyThread t1 = new MyThread(); MyThread t2 = new MyThread();
t1.setName("线程1"); t2.setName("线程2");
t1.start(); t2.start();
} } Lobster AIjava运行12345678910111213141516171819202122
|
1.3.2 实现Runnable接口的方式进行实现
创建线程的另一种方法是声明实现 Runable 接口的类。该类然后实现run方法。然后可以分配该类的实例,在创建Thread 时作为一个参数来传递并启动。采用这种风格的同一个例子如下所示:
1 2 3 4 5 6 7 8
| class PrimeRun implements Runnable { long minPrime; PrimeRun (1ong minPrime){ this. minPrime = minPrime; } public void run() Lobster AIjava运行1234567
|
然后,下列代码会创建并启动一个线程:
1 2 3
| PrimeRun P = new PrimeRun(143); new Thread(p). start() ; Lobster AIjava运行12
|
每个线程都有一个标识名,多个线程可以同名。如果线程创建时没有指定标识名,就会为其生成一个新名称。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class MyRun implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("helloworld"); } } }
Lobster AIjava运行123456789 public class main {
public static void main(String[] args){
MyRun mr = new MyRun(); Thread t1 = new Thread(mr); t1.start();
}
}
Lobster AIjava运行1234567891011121314151617
|
同样看不到,我们还是采用一些手段
1 2 3 4 5 6 7 8 9 10 11
| public class MyRun implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { Thread thread = Thread.currentThread(); System.out.println(thread.getName()+": helloworld"); } } }
Lobster AIjava运行12345678910
|
其中,Thread thread = Thread.currentThread();表示的是该时刻运行的是那个线程就指那个线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import java.lang.String;
public class main {
public static void main(String[] args){
MyRun mr = new MyRun(); Thread t1 = new Thread(mr); Thread t2 = new Thread(mr); t1.setName("线程1"); t2.setName("线程2"); t1.start(); t2.start();
}
} Lobster AIjava运行12345678910111213141516171819202122
|
1.3.3 利用Callable接口和Future接口方式实现
为什么会有第三种呢?其实是对前面两种的补充,前两种是没有返回值的,我想要多线程的结果所以第三种来了!!!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import java.util.concurrent.Callable; public class MyCallable implements Callable<Integer>{
@Override public Integer call() throws Exception { int sum =0; for (int i = 0; i <= 100; i++) { sum = sum + i; } return sum; } }
Lobster AIjava运行1234567891011121314 import java.io.File; import java.lang.String; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask;
public class main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable mc = new MyCallable(); FutureTask<Integer> ft = new FutureTask<>(mc); Thread t1 = new Thread(ft);
t1.start();
System.out.println(ft.get());
}
}
Lobster AIjava运行123456789101112131415161718192021222324252627
|

1.4 常见的成员方法

Mythread.java
1 2 3 4 5 6 7 8 9 10
| public class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName()+":"+i); } } }
Lobster AIjava运行123456789
|
Main.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import java.lang.String; public class main {
public static void main(String[] args){ MyThread t1 = new MyThread(); MyThread t2 = new MyThread();
t1.start(); t2.start();
}
}
Lobster AIjava运行12345678910111213141516171819202122
|
默认名字:Thread-X(0开始)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class MyThread extends Thread{ public MyThread() { }
public MyThread(String name) { super(name); }
@Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName()+":"+i); } } }
Lobster AIjava运行12345678910111213141516 import java.lang.String; public class main {
public static void main(String[] args){ MyThread t1 = new MyThread("小飞棍"); MyThread t2 = new MyThread("来喽");
t1.start(); t2.start(); } } Lobster AIjava运行1234567891011
|
观察下面的运行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import java.lang.String; public class main {
public static void main(String[] args){
Thread t1 = Thread.currentThread(); String name = t1.getName(); System.out.println(name);
}
} Lobster AIjava运行1234567891011121314
|
sleep方法

1.4.1 线程的优先级

随机性,线程的随机性,运行时间的随机性

线程轮流进行,执行时间也是差不多的

Java默认有10档 1到10 默认是5
查看优先级
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import java.lang.String; import java.util.SortedMap;
public class main {
public static void main(String[] args){
MyRun mr = new MyRun(); Thread t1 = new Thread(mr,"飞机"); Thread t2 = new Thread(mr,"坦克");
System.out.println(t1.getPriority()); System.out.println(t2.getPriority());
}
}
|
更换优先级
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import java.lang.String; import java.util.SortedMap;
public class main {
public static void main(String[] args){
MyRun mr = new MyRun(); Thread t1 = new Thread(mr,"飞机"); Thread t2 = new Thread(mr,"坦克"); t1.setPriority(1); t2.setPriority(10);
System.out.println(t1.getPriority()); System.out.println(t2.getPriority()); } }
|
1.4.2 守护线程 SetDaemon(boolean on)

细节: 当其他的非守护线程执行完毕之后,守护线程会陆续结束
通俗易懂: 当女神线程结束了,那么备胎也没有存在的必要了
备胎可能执行不完程序就结束了
同样!!!不说女神先执行完 而是同时执行
应用场景:

1.4.3 礼让线程 yield()(了解)

当遇到yield 抢夺权重新抢
1.4.4 插入线程 join()(了解)

1.4.5 线程的生命周期


1.5 线程安全的问题

Mythread.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class MyThread extends Thread{ static int ticket = 0;
@Override public void run() { while(true) { if(ticket<100) { try { Thread.sleep(500); } catch (InterruptedException e) { throw new RuntimeException(e); } ticket++; System.out.println(getName()+"正在卖第"+ticket+"张票"); } else break; } } }
Lobster AIjava运行1234567891011121314151617181920212223
|
main.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import java.lang.String; import java.util.SortedMap;
public class main {
public static void main(String[] args){
MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); MyThread t3 = new MyThread();
t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3");
t1.start(); t2.start(); t3.start();
}
}
Lobster AIjava运行1234567891011121314151617181920212223242526
|
上面代码有问题,有超出100的票 有重复的票 有的票没卖
1.5.1 同步代码块

因为线程在执行的时候,CPU的执行权随时会被抢走!!!
如果我们能把共享数据的这部分代码能够被锁起来,当我用的时候,别人抢不走

线程安全问题解决!!看下面代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class MyThread extends Thread{ static int ticket = 0;
static Object obj = new Object();
@Override public void run() { while(true) { synchronized (obj) { if(ticket<100) { try { Thread.sleep(500); } catch (InterruptedException e) { throw new RuntimeException(e); } ticket++; System.out.println(getName()+"正在卖第"+ticket+"张票"); } else break; } } } }
Lobster AIjava运行12345678910111213141516171819202122232425262728
|
1.5.2 同步代码块的两个小细节

如果锁不一样,那就没意义了
1.5.3 同步方法

- 特点1:同步方法是锁住方法里面所有的代码
- 特点2:锁对象不能自己指定
非静态:this
静态:当前类的字节码文件对象
记住快捷键Ctrl+Alt+M 方法生成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| import javax.xml.namespace.QName;
public class MyRun implements Runnable{
int ticket = 0;
@Override public void run() { while(true) {
if (method()) break;
}
}
private synchronized boolean method() { if(ticket<100) { try { Thread.sleep(500); } catch (InterruptedException e) { throw new RuntimeException(e); } ticket++; System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票"); } else return true; return false; } }
Lobster AIjava运行12345678910111213141516171819202122232425262728293031323334 import java.lang.String; import java.util.SortedMap;
public class main {
public static void main(String[] args){
MyRun mr = new MyRun(); Thread t1 = new Thread(mr); Thread t2 = new Thread(mr); Thread t3 = new Thread(mr);
t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3");
t1.start(); t2.start(); t3.start();
}
}
Lobster AIjava运行1234567891011121314151617181920212223242526
|
1.5.4 lock锁
有没有可能手动释放锁和加锁

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;
public class MyThread extends Thread{ static int ticket = 0;
static Lock lock = new ReentrantLock();
@Override public void run() { while(true) { lock.lock(); try { if(ticket<100) {
Thread.sleep(500); ticket++; System.out.println(getName()+"正在卖第"+ticket+"张票"); } else break; } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); }
} } }
Lobster AIjava运行12345678910111213141516171819202122232425262728293031323334
|
1.6 死锁
也就是锁出现了锁的嵌套
死锁是什么?是程序的错误,千万不要在程序中涉及死锁


1.7 生产者和消费者(等待唤醒机制第一种实现方式)
生产消费者模式是一个十分经典的多线程协作的模式



桌上上有面条,吃货来吃,没有面条,厨师来做
1.7.1 消费者等待
当第一次线权被吃货抢到,那就wait,那就厨师来做,做完之后,厨师负责唤醒notify。

1.7.1 生产者等待
当厨师抢到执行权,做好面条,执行权又被厨师抢到,那就等待wait


Cook.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public class Cook extends Thread { @Override public void run() {
while (true) { synchronized (Desk.lock) { if(Desk.count==0) { break; } else { if(Desk.foodFlag==0) { try { Desk.lock.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } else { Desk.count--;
System.out.println("吃货在吃,还可以吃 "+Desk.count+" 碗"); Desk.lock.notify();
Desk.foodFlag=0; } } } }
} }
Lobster AIjava运行1234567891011121314151617181920212223242526272829303132333435363738394041424344
|
Foodie.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class Foodie extends Thread{ @Override public void run() { while(true) { synchronized (Desk.lock) { if(Desk.count==0) { break; } else { if(Desk.foodFlag==1) { try { Desk.lock.wait(); } catch (InterruptedException e) { throw new RuntimeException(e); } } else { System.out.println("厨师正在做面条"); Desk.lock.notify(); Desk.foodFlag=1; } } } }
} }
Lobster AIjava运行1234567891011121314151617181920212223242526272829303132333435
|
Desk.java
1 2 3 4 5 6 7 8 9 10 11
| public class Desk {
public static int foodFlag = 0;
public static int count = 10;
public static Object lock = new Object();
}
Lobster AIjava运行12345678910
|
Main.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import java.lang.String; public class main {
public static void main(String[] args){
Cook cook = new Cook(); Foodie foodie = new Foodie(); cook.setName("吃货"); foodie.setName("厨师"); cook.start(); foodie.start();
}
}
Lobster AIjava运行1234567891011121314151617
|
1.8 阻塞队列(等待唤醒机制第二种实现方式)

我们可以规定管道中最多放多少面条

1.8.1 阻塞队列的继承结构
它一共继承了4个接口
- Iterable (可以用增强For和迭代器遍历)
- Collection
- Queue
- BlockingQueue

- ArrayBloackingQueue:底层是数组,有界(需要指定队列的长度)
- LinkedBlockingQueue:底层是链表,无界,但不是真正的无界,最大为int的最大值(不需要指定队列长度)
需求:利用阻塞队列完成生产者和消费者(等待唤醒机制)的代码
细节:生产者和消费者必须使用同一个阻塞队列
Cook.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import java.util.concurrent.ArrayBlockingQueue;
public class Cook extends Thread {
ArrayBlockingQueue<String> queue;
public Cook(ArrayBlockingQueue<String> queue) { this.queue = queue; }
@Override public void run() { while(true) { try { queue.put("面条"); System.out.println("厨师做了1晚面条"); } catch (InterruptedException e) { throw new RuntimeException(e); } }
} }
Lobster AIjava运行123456789101112131415161718192021222324252627
|
Foodie.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import java.util.concurrent.ArrayBlockingQueue;
public class Foodie extends Thread{
ArrayBlockingQueue<String> queue;
public Foodie(ArrayBlockingQueue<String> queue) { this.queue = queue; }
@Override public void run() { while(true) { try { String food = queue.take(); System.out.println("吃货在吃面"); } catch (InterruptedException e) { throw new RuntimeException(e); } }
} }
Lobster AIjava运行1234567891011121314151617181920212223242526
|
main.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| import java.lang.String; import java.util.concurrent.ArrayBlockingQueue;
public class main {
public static void main(String[] args){
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);
Cook cook =new Cook(queue); Foodie foodie = new Foodie(queue);
cook.setName("吃货"); foodie.setName("厨师");
cook.start(); foodie.start();
}
}
Lobster AIjava运行123456789101112131415161718192021222324 厨师做了1晚面条 厨师做了1晚面条 吃货在吃面 厨师做了1晚面条 吃货在吃面 吃货在吃面 厨师做了1晚面条 厨师做了1晚面条 吃货在吃面 厨师做了1晚面条 吃货在吃面 吃货在吃面 厨师做了1晚面条 厨师做了1晚面条 吃货在吃面 吃货在吃面 厨师做了1晚面条 厨师做了1晚面条 吃货在吃面 厨师做了1晚面条 吃货在吃面 厨师做了1晚面条 厨师做了1晚面条 吃货在吃面 吃货在吃面 Lobster AIjava运行12345678910111213141516171819202122232425
|
为什么我限制了一碗,不说ABAB那样展示,因为输出语句是咋锁的外面的,但是运行没问题
1.8.2 线程的状态
回顾

但是上面不完整,看下面的七大状态

java是没有定义运行状态的,当运行的时候,交给操作系统了,虚拟机不管了。

1.9 综合练习
1.9.1 买电影票
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| public class MyThread extends Thread{
static int ticket = 1000;
@Override public void run() { while(true) { synchronized (MyThread.class) { if(ticket==0) { break; } else { ticket--; try { Thread.sleep(3000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(getName()+"正在出售,还有"+ticket+"张在售"); } } }
} }
Lobster AIjava运行123456789101112131415161718192021222324252627282930 import java.lang.String; import java.util.concurrent.ArrayBlockingQueue;
public class main {
public static void main(String[] args){
MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread();
myThread1.setName("售票口1"); myThread2.setName("售票口2");
myThread1.start(); myThread2.start();
}
}
Lobster AIjava运行12345678910111213141516171819202122
|
1.9.2 抢红包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| import java.util.Random;
public class MyThread extends Thread{
static double hongbao = 100;
static int num = 3;
@Override public void run() {
synchronized (MyThread.class) { if(num == 0) { System.out.println(getName()+"没抢到"); } else { double price=0; if(num == 1) { price = hongbao; } else { Random r = new Random(); double bounds = hongbao-(num-1)*0.01; price = r.nextDouble(bounds); if(price<0.01)price =0.01;
} hongbao = hongbao - price; System.out.println(getName()+"抢到了"+price+"元"); num--; } } } }
Lobster AIjava运行12345678910111213141516171819202122232425262728293031323334353637383940 import java.lang.String; import java.util.concurrent.ArrayBlockingQueue;
public class main {
public static void main(String[] args){
MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); MyThread myThread3 = new MyThread(); MyThread myThread4 = new MyThread(); MyThread myThread5 = new MyThread();
myThread1.setName("张三"); myThread2.setName("李四"); myThread3.setName("王五"); myThread4.setName("赵六"); myThread5.setName("小白");
myThread1.start(); myThread2.start(); myThread3.start(); myThread4.start(); myThread5.start();
}
}
Lobster AIjava运行12345678910111213141516171819202122232425262728293031323334
|
1.9.3 抽奖

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Random;
public class MyThread extends Thread{
ArrayList<Integer> list;
public MyThread(ArrayList<Integer> list) { this.list = list; }
@Override public void run() { while (true) { synchronized (MyThread.class) { if(list.size()==0) { System.out.println("抽完了"); break; } else { Collections.shuffle(list); int price = list.remove(0); System.out.println(getName()+"产生了一个"+price+"元大奖");
} } try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } }
} }
Lobster AIjava运行12345678910111213141516171819202122232425262728293031323334353637383940414243 import java.lang.String; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.concurrent.ArrayBlockingQueue;
public class main {
public static void main(String[] args){
ArrayList<Integer> arrayList = new ArrayList<>(); Collections.addAll(arrayList,10,5,20,50,100,200,500,800,2,80,300,700); MyThread myThread1 = new MyThread(arrayList); MyThread myThread2 = new MyThread(arrayList);
myThread1.setName("抽奖箱1"); myThread2.setName("抽奖箱2");
myThread1.start(); myThread2.start();
}
} Lobster AIjava运行1234567891011121314151617181920212223242526
|
1.9.4 多线程统计

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Random;
public class MyThread extends Thread{
ArrayList<Integer> list;
static ArrayList<Integer> arrayList1 = new ArrayList<>(); static ArrayList<Integer> arrayList2 = new ArrayList<>();
public MyThread(ArrayList<Integer> list) { this.list = list; }
@Override public void run() { while (true) { synchronized (MyThread.class) { if(list.size()==0) { if("抽奖箱1".equals(getName())) { System.out.println(getName()+arrayList1); } else { System.out.println(getName()+arrayList2); } break; } else { Collections.shuffle(list); int price = list.remove(0); if("抽奖箱1".equals(getName())) { arrayList1.add(price); } else { arrayList2.add(price); }
} } try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } }
} }
Lobster AIjava运行12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 import java.lang.String; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.concurrent.ArrayBlockingQueue;
public class main {
public static void main(String[] args){
ArrayList<Integer> arrayList = new ArrayList<>(); Collections.addAll(arrayList,10,5,20,50,100,200,500,800,2,80,300,700); MyThread myThread1 = new MyThread(arrayList); MyThread myThread2 = new MyThread(arrayList);
myThread1.setName("抽奖箱1"); myThread2.setName("抽奖箱2");
myThread1.start(); myThread2.start();
}
}
Lobster AIjava运行1234567891011121314151617181920212223242526272829303132
|
1.9.5 线程栈
如果上面的抽奖箱有100个 难道要创建100个ArrayList嘛?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Random;
public class MyThread extends Thread{
ArrayList<Integer> list;
public MyThread(ArrayList<Integer> list) { this.list = list; }
@Override public void run() { ArrayList<Integer> boxList = new ArrayList<>(); while (true) { synchronized (MyThread.class) { if(list.size()==0) { System.out.println(getName()+boxList);
break; } else { Collections.shuffle(list); int price = list.remove(0); boxList.add(price);
} } try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } }
} }
Lobster AIjava运行1234567891011121314151617181920212223242526272829303132333435363738394041424344
|

内存中,堆是唯一的!但是栈!是跟线程有关的!也就是说一个线程就有一个栈!!!!



1.9.6 多线程比较

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| import com.sun.source.tree.BreakTree;
import javax.swing.*; import java.util.ArrayList; import java.util.Collections; import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer>{
ArrayList<Integer> list;
public MyCallable(ArrayList<Integer> list) { this.list = list; }
@Override public Integer call() throws Exception{ ArrayList<Integer> boxList = new ArrayList<>(); while (true) { synchronized (MyThread.class) { if(list.size()==0) { System.out.println(Thread.currentThread().getName()+boxList);
break; } else { Collections.shuffle(list); int price = list.remove(0); boxList.add(price);
} } try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } }
if(boxList.size()==0) return null; else { return Collections.max(boxList); }
}
}
Lobster AIjava运行123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354 import java.lang.String; import java.util.ArrayList; import java.util.Collections; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask;
public class main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ArrayList<Integer> arrayList = new ArrayList<>(); Collections.addAll(arrayList,10,5,20,50,100,200,500,800,2,80,300,700); MyCallable mc = new MyCallable(arrayList);
FutureTask<Integer> ft1 = new FutureTask<>(mc); FutureTask<Integer> ft2 = new FutureTask<>(mc);
Thread myThread1 = new Thread(ft1); Thread myThread2 = new Thread(ft2);
myThread1.setName("抽奖箱1"); myThread2.setName("抽奖箱2");
myThread1.start(); myThread2.start();
System.out.println(ft1.get());
System.out.println(ft2.get());
}
}
Lobster AIjava运行12345678910111213141516171819202122232425262728293031323334353637383940
|
1.10 线程池



线程池诞生!!!!
线程池主要核心原理,
- ①创建一个池子,池子中是空的
- ②提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子,下回再次提交任务时,不需要创建新的线程,直接复用已有的线程即可
- ③但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import javax.xml.namespace.QName;
public class MyRun implements Runnable{
@Override public void run() { System.out.println(Thread.currentThread().getName()+"-----------------");
}
}
Lobster AIjava运行1234567891011121314 import java.lang.String; import java.util.ArrayList; import java.util.Collections; import java.util.concurrent.*;
public class main {
public static void main(String[] args) throws InterruptedException {
ExecutorService pool1 = Executors.newCachedThreadPool();
pool1.submit(new MyRun()); Thread.sleep(1000); pool1.submit(new MyRun());Thread.sleep(1000); pool1.submit(new MyRun());Thread.sleep(1000); pool1.submit(new MyRun());Thread.sleep(1000); pool1.submit(new MyRun());
}
}
Lobster AIjava运行1234567891011121314151617181920212223242526272829
|
1.11 自定义线程池超详细解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import java.lang.String; import java.util.ArrayList; import java.util.Collections; import java.util.concurrent.*;
public class main {
public static void main(String[] args) throws InterruptedException {
ExecutorService pool1 = Executors.newFixedThreadPool(3);
pool1.submit(new MyRun()); pool1.submit(new MyRun()); pool1.submit(new MyRun()); pool1.submit(new MyRun()); pool1.submit(new MyRun());
}
}
Lobster AIjava运行12345678910111213141516171819202122
|
我们约束了3个线程,但是不够灵活,当我提交的任务足够多的时候




什么时候会创建临时线程——当我的队伍排满的时候!我才会去创建临时线程
不是说先到先服务
什么时候才会拒绝服务!看下面:

拒绝策略的方法:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import java.lang.String; import java.util.concurrent.*;
public class main {
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor pool = new ThreadPoolExecutor( 3, 6, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy() ); }
}
|
自定义线程池小结:
- ①创建一个空的池子
- ②有任务提交时,线程池会创建线程去执行任务,执行完毕归还线程
不断的提交任务,会有以下三个临界点:
- ①当核心线程满时,再提交任务就会排队
- ②当核心线程满,队伍满时,会创建临时线程
- ③当核心线程满,队伍满,临时线程满时,会触发任务拒绝策略
1.12 最大并行数

什么是最大并行数?
这个与CPU有关,比如4核8线程

4核:CPU有4个大脑——可以做四件事情
因特尔发明了——超线程技术(分身),把4个大脑虚拟成8个


1.13 线程池多大合适
这个要看自己的项目是什么类型的?——有两种类型
- CPU密集型运算
如果我的项目计算比较多,或者访问数据库比较少,读取本地文件少
- I/O密集型运算

1.14 多线程的额外扩展内容

以上内容是面试要会的内容,实际开发可能很少遇到。
2 网络编程
2.1 什么是网络编程?
- 在网络通信协议下,不同计算机上运行的程序,进行的数据传输。
- 应用场景:即时通信、网游对战、金融证券、国际贸易、邮件、等等。
不管是什么场景,都是计算机跟计算机之间通过网络进行数据传输。
- java中可以使用java.net包下的技术开发出常见的网络应用程序。
- 常见的网络架构:BS、CS

比如QQ,Steam

一般大厂 两种都会兼顾

BS架构的优缺点
- 不需要开发客户端,只需要页面+服务端
- 用户不需要下载,打开浏览器就能使用
- 如果应用过大,用户体验受到影响
CS架构的优缺点
- 画面可以做的非常精美,用户体验好
- 需要开发客户端,也需要开发服务端
- 用户需要下载和更新的时候太麻烦
2.2 网络编程三要素
- IP 设备在网络中的地址,是唯一的标识。
- 端口号 应用程序在设备中唯一的标识。
- 协议 数据在网络中传输的规则,常见的协议有UDP、TCP、http、 https、 ftp。
2.2.1 IP
- 全称: Internet Protocol,是互联网协议地址,也称IP地址。
是分配给上网设备的数字标签。
- 通俗理解:上网设备在网络中的地址,是唯一的
- 常见的IP分类为:IPv4、IPv6
IPv4
全称: Internet Protocol version4,互联网通信协议第四版


每一组是0~255 没有负数
但是也就43亿的IP,不够使用,2019年就应该分配完了。
所以IPv6来喽!


2.2.2 IPv4的地址分类
每个网卡有一个IP地址

他们下面的共享一个公网IP,然后由路由器分配局域网IP


不一样!
假设 我现在局域网有6个设别,都是有路由器分配的。


当你换了网上网, 你的局域网的IP就会更改。

自己给自己发数据,那就用127.0.0.1
- ipconfig:查看本机IP地址
- ping:检查网络是否连通
2.2.3 InetAddress的使用
这个对象就表示IP的对象

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import java.lang.String; import java.net.InetAddress; import java.net.UnknownHostException;
public class main {
public static void main(String[] args) throws UnknownHostException { InetAddress address = InetAddress.getByName("DESKTOP-JL38L7P"); System.out.println(address);
String name = address.getHostName(); System.out.println(name);
String ip = address.getHostAddress(); System.out.println(ip);
}
}
|
2.2.4 端口号
应用程序在设备中唯一的标识。
端口号:由两个字节表示的整数,取值范围: 0~65535
其中0~1023之间的端口号用于一些知名的网络服务或者应用。我们自己使用1024以上的端口号就可以了。
注意:一个端口号只能被一个应用程序使用。

2.2.5 协议
计算机网络中,连接和通信的规则被称为网络通信协议
- OSI参考模型:世界互联协议标准,全球通信规范,单模型过于理想化,未能在因特网上进行广泛推广
- TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。

OSI:

TCP/IP:

UDP协议
- 用户数据报协议(User Datagram Protocol)
- UDP 是面向无连接通信协议。
- 速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据
网络会议、在线视频、视频聊天
TCP协议
- 传输控制协议TCP(Transmission Control Protocol)
- TCP协议是面向连接的通信协议。
- 速度慢,没有大小限制,数据安全。
发送邮件、下载软件、发送消息
2.3 UDP通信程序
2.3.1 UDP发送通信程序


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import java.io.IOException; import java.lang.String; import java.net.*; import java.nio.charset.StandardCharsets;
public class main {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
String str = "你好帅"; byte[] bytes = str.getBytes(); InetAddress address = InetAddress.getByName("127.0.0.1"); int port = 10086; DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
ds.send(dp);
ds.close();
} }
|
2.3.2 UDP接送通信程序


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException;
public class ReceiveMessageDemo { public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(10086);
byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes,bytes.length); ds.receive(dp);
byte[] data = dp.getData(); int len = dp.getLength();
InetAddress address = dp.getAddress(); int port = dp.getPort();
System.out.println("接受的数据"+new String(data,0,len)); System.out.println("该数据是从 "+address+" 这台电脑的 "+port+" 端口发出的");
ds.close();
} }
|
receive会死等,先运行接受,再运行发送
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import java.io.IOException; import java.lang.String; import java.net.*; import java.nio.charset.StandardCharsets;
public class main {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
String str = "你好帅"; byte[] bytes = str.getBytes(); InetAddress address = InetAddress.getByName("127.0.0.1"); int port = 10086; DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
ds.send(dp);
ds.close();
}
}
|
2.3.3 UDP聊天室小练习

ReceiveMessageDemo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException;
public class ReceiveMessageDemo { public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(10086);
byte[] bytes = new byte[1024]; DatagramPacket dp = new DatagramPacket(bytes,bytes.length); while (true) {
ds.receive(dp); byte[] data = dp.getData(); int len = dp.getLength(); String hostAddress = dp.getAddress().getHostAddress(); String hostName = dp.getAddress().getHostName();
System.out .println("ip为:"+ hostAddress + ",主机名为"+ hostName + "的人,发送了数据: " + new String(data,0,len));
}
} }
|
SendMessageDemo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import java.io.IOException; import java.net.*; import java.util.Scanner;
public class SendMessageDemo { public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket();
Scanner sc = new Scanner(System.in); while (true) { System.out.println("请输入:"); String str = sc.nextLine(); if("886".equals(str)) { break; } byte[] bytes = str.getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1"); int port = 10086; DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
ds.send(dp);
}
ds.close();
}
}
|
2.3.4 UDP三种通信方式
以前的代码就是单播的
组播地址:224.0.0.0239.255.255.255
其中224.0.0.0224.0.0.255为预留的组播地址


广播地址255.255.255.255

2.4 TCP通信程序


客户端
- 创建客户端的Socket对象(Socket)与指定服务端连接
Socket(String host, int port)
- 获取输出流,写数据
OutputStream getOutputStream( )
- 释放资源
void close()
服务器
- 创建服务器端的Socket对象(ServerSocket)
ServerSocket(int port)
- 监听客户端连接,返回一个Socket对象
Socket accept( )
- 获取输入流,读数据,并把数据显示在控制台
InputStream getInputStream( )
- 释放资源
void close()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket;
public class Server { public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086);
Socket socket = ss.accept();
InputStream is = socket.getInputStream();
int b; while ((b=is.read())!=-1) { System.out.println((char)b); } socket.close(); ss.close();
} }
Lobster AIjava运行12345678910111213141516171819202122232425 import java.io.IOException; import java.io.OutputStream; import java.net.Socket;
public class Client { public static void main(String[] args) throws IOException { Socket socket = new Socket("127.0.0.1",10086);
OutputStream os = socket.getOutputStream(); os.write("你好你好".getBytes());
os.close(); socket.close();
} }
Lobster AIjava运行1234567891011121314151617
|
上面出现了中文乱码的现象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket;
public class Server { public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086);
ss.accept();
Socket socket = ss.accept();
InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); int b; while ((b=br.read())!=-1) { System.out.print((char)b); } socket.close(); ss.close();
} }
Lobster AIjava运行123456789101112131415161718192021222324252627282930
|

2.4.1 三次握手协议



2.4.2 四次挥手协议



2.5 综合练习
2.5.1 多发多收

Server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket;
public class Server { public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086); while (true) {
Socket socket = ss.accept(); InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr);
int b; while((b= br.read())!=-1) { System.out.print((char)b); } System.out.println();
}
} }
Lobster AIjava运行123456789101112131415161718192021222324252627282930313233
|
Client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.util.Scanner;
public class Client { public static void main(String[] args) throws IOException { Socket socket = new Socket("127.0.0.1",10086); OutputStream os = socket.getOutputStream();
while(true) { Scanner sc = new Scanner(System.in); System.out.println("请输入:(输入886退出聊天)"); String str = sc.nextLine(); if("886".equals(str)) { break; } else { os.write(str.getBytes()); } } os.close(); socket.close();
} }
Lobster AIjava运行12345678910111213141516171819202122232425262728293031
|
2.5.2 接收并反馈

Server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import java.io.*; import java.net.ServerSocket; import java.net.Socket;
public class Server { public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086); System.out.println("等待客户端连接"); Socket socket = ss.accept(); System.out.println("客户端连接完成");
InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); int b; System.out.println("准备读取客户端发送过来的数据"); while((b = isr.read())!=-1) { System.out.println("正在读取"); System.out.println((char) b); } System.out.println("读取完毕,准备回写");
String str = "NTMD"; OutputStream os = socket.getOutputStream(); os.write(str.getBytes()); System.out.println("回写成功"); socket.shutdownOutput(); os.close();
} }
Lobster AIjava运行12345678910111213141516171819202122232425262728293031323334
|
Client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import java.io.*; import java.net.Socket; import java.util.Scanner;
public class Client { public static void main(String[] args) throws IOException { Socket socket = new Socket("127.0.0.1",10086);
String str = "见到你很高兴!"; OutputStream os = socket.getOutputStream(); os.write(str.getBytes()); socket.shutdownOutput();
InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); int b; while((b = isr.read())!=-1) { System.out.println((char) b); }
os.close(); socket.close();
} }
Lobster AIjava运行12345678910111213141516171819202122232425262728
|
2.5.3 上传文件

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| import java.io.*; import java.net.ServerSocket; import java.net.Socket;
public class Server { public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086); Socket socket = ss.accept();
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream()); BufferedOutputStream bos = new BufferedOutputStream (new FileOutputStream("F:\\QQ_DownLoad_Document\\Ma.pdf"));
int len; byte[] bytes = new byte[1024]; while((len=bis.read(bytes))!= -1) { bos.write(bytes,0,len); } bos.flush();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bw.write("上传成功"); bw.newLine();
bw.flush();
socket.close(); ss.close();
} }
Lobster AIjava运行12345678910111213141516171819202122232425262728293031323334 import java.io.*; import java.net.Socket; import java.util.Scanner;
public class Client { public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",10086);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream ("F:\\QQ_DownLoad_Document\\Xu Ma.pdf")); BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] bytes = new byte[1024]; int len; while((len= bis.read(bytes))!=-1) { bos.write(bytes,0,len); } bos.flush(); socket.shutdownOutput();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String s = br.readLine(); System.out.println(s);
socket.close();
} }
Lobster AIjava运行123456789101112131415161718192021222324252627282930313233
|
2.5.4 文件名重复

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.UUID;
public class Server { public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086); Socket socket = ss.accept();
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream()); String sttr = UUID.randomUUID().toString().replace("-",""); BufferedOutputStream bos = new BufferedOutputStream (new FileOutputStream("F:\\QQ_DownLoad_Document\\"+sttr+".pdf"));
int len; byte[] bytes = new byte[1024]; while((len=bis.read(bytes))!= -1) { bos.write(bytes,0,len); } bos.flush();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bw.write("上传成功"); bw.newLine();
bw.flush();
socket.close(); ss.close();
} }
Lobster AIjava运行123456789101112131415161718192021222324252627282930313233343536
|
String sttr = UUID.randomUUID().toString().replace("-",""); 跟平常在网站上下载的一些图片,视频 一堆乱码的名字原理!!!!!!!!!!!!!!!!
2.5.5 多线程版的服务端

MyRunnable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import java.io.*; import java.net.Socket; import java.util.UUID;
public class MyRunnable implements Runnable { Socket socket; public MyRunnable(Socket socket) { this.socket = socket; }
@Override public void run() { try { BufferedInputStream bis = new BufferedInputStream(socket.getInputStream()); String sttr = UUID.randomUUID().toString().replace("-",""); BufferedOutputStream bos = new BufferedOutputStream (new FileOutputStream("F:\\QQ_DownLoad_Document\\"+sttr+".pdf"));
int len; byte[] bytes = new byte[1024]; while((len=bis.read(bytes))!= -1) { bos.write(bytes,0,len); } bos.flush();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); bw.write("上传成功"); bw.newLine();
bw.flush(); } catch (IOException e) { throw new RuntimeException(e); } finally { if(socket !=null) { try { socket.close(); } catch (IOException e) { throw new RuntimeException(e); } } }
} }
Lobster AIjava运行123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
|
Server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.UUID;
public class Server { public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10086); while (true) { Socket socket = ss.accept();
new Thread(new MyRunnable(socket)).start(); }
} }
Lobster AIjava运行12345678910111213141516171819
|
2.5.6 线程池版的服务端



2.5.7 BS架构模型


在BS架构中,我们的客户端就是浏览器,服务端就是接受浏览器的发送内容
3 反射
3.1 反射的概述
反射允许对封装类的字段,方法和构造函数的信息进行编程访问。

提示的方法就是通过反射来实现的
Ctrl+P 反射可以获得我忘了的形参


3.2 获取class对象的三种方式
获取class对象的三种方式
- Class. forName(“全类名”);
- 类名. class
- 对象. getClass();


3.3 反射获取构造方法

3.4 反射获取成员变量

3.5 反射获取成员方法

4 动态代理
4.1 动态代理的思想分析
如果我想着要我的类中的成员方法添加我想要的。 如果直接添加——侵入式修改
如果我不想修改原来的代码,又想添加功能,怎么办???

所以动态代理!!!
特点:无侵入式的给代码增加额外的功能


对象有什么方法想被代理,代理就一定要有对应的方法



4.2 动态代理的代码实现
