网络编程
多线程的作业
Ticket.java
package com.qfedu.homework;
public class Ticket implements Runnable{
private int ticket = 100;
@Override
public void run() {
try {
while(true) {
//Thread.sleep(100);
sellTicket();
if(ticket <= 0) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 卖票的方法
*/
public synchronized void sellTicket() {
if(ticket > 0) {
System.out.println(Thread.currentThread().getName() + "正在售出第" + ticket-- + "张票");
}
}
}
TicketTest.java
package com.qfedu.homework;
public class TicketTest {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread t1 = new Thread(ticket, "12306");
Thread t2 = new Thread(ticket, "火车站");
Thread t3 = new Thread(ticket, "代售点");
Thread t4 = new Thread(ticket, "黄牛");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
命名规范
-
驼峰命名法则
- 一般用于变量,方法命名
2. 比如setName, main, getUsername,money
- 一般用于变量,方法命名
-
Pascal命名法
- 一般用于类名,接口名,枚举类型名,注解类型名
2. HelloWorld, Days02Net, Ticket, TicketTest
- 一般用于类名,接口名,枚举类型名,注解类型名
-
匈牙利命名法
- 一般用于控件命名,给给定变量前或者后,添加额外的前缀或者后缀
2. txtUsername, lblAge, btnSubmit
- 一般用于控件命名,给给定变量前或者后,添加额外的前缀或者后缀
-
全大写
- 一般用于常量命名
2. MAX_PRIORITY, MALE, FEMALE, MAX_VALUE
- 一般用于常量命名
-
全小写
- 一般用于包名
2. com.baidu, com.qfedu
小贴士:
4代表four,进一步代表for, log4j
2代表two,进一步代表to, rmb2Usd
编码规范,自行下载一个大型公司的编码规范 阿里规范
- 一般用于包名
锁机制
1. **synchronized** 关键字
1. 同步代码块,锁为任意的非空对象,注意不能放基本类型的数据
2. 同步方法,锁为this
3. 静态同步方法,锁为类.class类对象
2. ReentrantLock API
1. lock
2. unlock
PayMoney.java
package com.qfedu.lock;
import java.util.concurrent.locks.ReentrantLock;
public class PayMoney implements Runnable {
int money = 5000 * 3;
static int money2 = 5000 * 3;
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
for (int i = 0; i < 10; i++) {
// pay();
// pay02();
// pay03();
// pay04();
pay05();
}
}
// 会出现临界资源问题的代码
public void pay() {
System.out.println(Thread.currentThread().getName() + "目前余额" + money);
money -= 500;
System.out.println(Thread.currentThread().getName() + "付款完余额" + money);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 同步对象锁
public void pay02() {
synchronized ("") { //同步代码块
System.out.println(Thread.currentThread().getName() + "目前余额" + money);
money -= 500;
System.out.println(Thread.currentThread().getName() + "付款完余额" + money);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// 同步方法锁
public synchronized void pay03() {
System.out.println(Thread.currentThread().getName() + "目前余额" + money);
money -= 500;
System.out.println(Thread.currentThread().getName() + "付款完余额" + money);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 静态同步方法
*/
public synchronized static void pay04() {
System.out.println(Thread.currentThread().getName() + "目前余额" + money2);
if (money2 >= 500)
money2 -= 500;
System.out.println(Thread.currentThread().getName() + "付款完余额" + money2);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 使用ReentrantLock类来实现同步的锁的功能
*/
public void pay05() {
lock.lock(); // 上锁代码,之后的所有代码将以“独占”的方式执行,知道unlock()出现
System.out.println(Thread.currentThread().getName() + "目前余额" + money2);
if (money >= 500)
money2 -= 500;
System.out.println(Thread.currentThread().getName() + "付款完余额" + money2);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock(); // 解锁,之前锁定的代码就可以开放被下一个线程对象来访问执行
}
}
}
PayMoneyTest.java
package com.qfedu.lock;
public class PayMoneyTest {
public static void main(String[] args) {
PayMoney pm = new PayMoney();
Thread t1 = new Thread(pm, "迪丽热巴");
Thread t2 = new Thread(pm, "马尔扎哈");
Thread t3 = new Thread(pm, "全智贤");
t1.start();
t2.start();
t3.start();
}
}
生产者消费者问题
BreadFactory.java
package com.qfedu.procon;
public class BreadFactory {
private final static int MAX_NUM = 5000; // 仓库的最大容量
private int currentNum; // 当前仓库库存
public void setCurrentNum(int currentNum) {
this.currentNum = currentNum;
}
/**
*
* 生产者的生产方法
*
* @param num 生产者要生产的数量
*/
public synchronized void produce(int num) {
System.out.println("当前面包库存有" + currentNum + ",尝试生产面包数为" + num);
try {
Thread.sleep(100);
while(true) {
if(num + currentNum > MAX_NUM) { //要生产的面包数加上当前面包数大雨库存
System.out.println("容量不足,暂停生产...");
wait();
}else {
break;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
currentNum += num; // 当前库存更新
System.out.println("成功生产了" + num + "箱面包,当前库存为" + currentNum);
notify(); // 唤醒线程队列中的任意一个随机线程来执行
}
/**
*
* 消费者的消费方法
*
* @param num 消费者要消费的数量
*/
public synchronized void consume(int num) {
System.out.println("当前库存为" + currentNum + ",尝试要消费面包数为" + num);
try {
Thread.sleep(100);
while(true) {
if(num > currentNum) {
System.out.println("库存不足,无法消费...");
wait();
}else {
break;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
currentNum -= num;
System.out.println("成功消费了" + num + "箱面包,当前库存为" + currentNum);
notify();
}
}
Producer.java
package com.qfedu.procon;
public class Producer implements Runnable {
private BreadFactory bf;
private int num;
/**
* 在指定工厂中消费指定数量的面包
* @param bf 要生产的工厂对象
* @param num 要生产的面包数
*/
public Producer(BreadFactory bf, int num) {
this.bf = bf;
this.num = num;
}
@Override
public void run() {
// 在bf工厂中生产num箱面包
bf.produce(num);
}
}
Consumer.java
package com.qfedu.procon;
public class Consumer implements Runnable {
private BreadFactory bf;
private int num;
/**
* 在指定工厂中消费指定数量的面包
* @param bf 要消费的工厂对象
* @param num 要消费的面包数
*/
public Consumer(BreadFactory bf, int num) {
this.bf = bf;
this.num = num;
}
@Override
public void run() {
// 在bf工厂中消费num箱面包
bf.consume(num);
}
}
TestBreakFactory.java
package com.qfedu.procon;
public class TestBreakFactory {
public static void main(String[] args) {
BreadFactory bf = new BreadFactory();
bf.setCurrentNum(100);
// 在指定的面包工厂中创建4个生产者对象,并指定要生产的数量
Producer p1 = new Producer(bf, 500);
Producer p2 = new Producer(bf, 500);
Producer p3 = new Producer(bf, 800);
Producer p4 = new Producer(bf, 1200);
// 在指定的面包工厂中创建4个消费者对象,并指定要消费的数量
Consumer c1 = new Consumer(bf, 600);
Consumer c2 = new Consumer(bf, 400);
Consumer c3 = new Consumer(bf, 700);
Consumer c4 = new Consumer(bf, 400);
Thread t1 = new Thread(p1);
Thread t2 = new Thread(p2);
Thread t3 = new Thread(p3);
Thread t4 = new Thread(p4);
Thread t5 = new Thread(c1);
Thread t6 = new Thread(c2);
Thread t7 = new Thread(c3);
Thread t8 = new Thread(c4);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
t8.start();
}
}
sleep与wait对比
共同点:都会抛出InterruptedException异常
sleep
1. 休息指定时间,自动处于可运行状态
2. 不释放锁
3. Thread类的静态方法,只能通过Thread类或者对象来引入
4. Thread 类中有两个重载的方法
wait
1. 等待,需要被唤醒(notify/notifyAll方法)
2. 会释放锁
3. Object的方法,哪里都可以使用
4. Object类中有三个重载的方法
网络编程
计算机网络
网络七层架构
TCP/UDP
2.11作业
- 完成生产者消费者代码的编写(三遍)
- 翻阅jdk文档熟悉Object类,Thread类,ReentrantLock类中是所有内容
- 预习网络编程内容
- 同步代码块,同步方法
- Lock