说明
- TCP在建立连接与断开连接时报文头部的标志位与序号值分别是多少呢?
- 利用Java的Socket对象分别实现客户端与服务端,对进通讯过程进行数据报文捕获;
- 分别研究两种情况,一种是服务器与客户端都在本机,另一种是分别位于两台机器上;
Java示例代码
Client
// packag[......]
Client
// packag[......]
多个线程访问共享数据就会产生冲突的问题,以卖票为例,多个窗口卖同一批票就会出现重复卖的问题
public static void main(String[] args) {
Runnable runnable = new Runnable() {
Integer tickets = 100;
@Override
public void run() {
String name = Thread.currentThread().getName();
while(tickets-- > 0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + "正在卖票: " + tickets);
}
}
};
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
}
解决方案一:使用同步机制,共享部分同步执行则不会出现重复操作问题
synchronized
关键字实现代码块同步
public static void main(String[] args) {
Object lock = new Object();
Runnable runnable = new Runnable() {
Integer tickets = 100;
@Override
public void run() {
String name = Thread.currentThread().getName();
while (true) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock) {
if (tickets <= 0) break;
System.out.println(name + "正在卖票: " + tickets);
tickets--;
}
}
}
};
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
}
synchronized
同步方法实现同步机制
static Integer tickets = 100;
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
sellTicked();
if (tickets <= 0) break;
}
}
};
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
}
synchronized private static void sellTicked() {
if (tickets <= 0) return;
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖票: " + tickets);
tickets--;
}
解决方案二:使用锁,ReentrantLock
[……]
Thread
重写run
方法
public class MyThread extends Thread {
@Override
public void run() {
System.out.println(getName());
S[......]
List
与Set
ArrayList
、LinkedList
、Vector
;H[......]
byte b = 126;
// 按常理2是int型,byte + int 结果应该是int,但这里会强转为byte
b += 2; // 结果会溢出
System.out.println(b); // -128
OperationDemo.java:10: 错误: 不是语句
a > b ? a : b;
^
1 个错误
byte a = 10;
byte b = 20;
// 事实上是byte = int + int,所以编译时会报错
byte ret = a + b;
OperationDemo.java:5: 错误: 不兼容的类型: 从int转换到byte可能会有损失
byte ret = a + b;
^
1 个错误
// 上述示例中ret = a + b,表达式右边是int型,左边是byte,有转换失真的风险所以编译会报错;
// 但如果右边是常量则不会,byte ret = 10 + 20类似直接写byte ret = 30;
byte ret = 10 + 20;
public static int sum(int a, int b) {
return a + b;
}
// 编译报错,方法重名了,仅返回值类型不同不构成方法重载
public static float sum(int a, int b) {
return (float) (a + b);
}
0
,即int为0
、float为0.0
、对象为null
、char为\u0000
;
// 动态初始化,在创建数组时指定数组长度
int[] array1 = new int[10];
System.out.println(array1);
int[] array2 = new int[10];
System.out.println(array2);
// 静态初始化,创建数组时直接以数据长度为准
int[] array3 = new int[] {1, 2, 3, 4};
System.out.println(array3);
int[] array4 = {1, 2, 3, 4};
System.out.println(array4);
// 初始化可以先定义变量再赋值,但有一种情况例外
int[] array5;
array5 = new int[10];
int[] array6;
array6 = new int[] {1, 2, 3, 4};
int[] array7;
array7 = {1, 2, 3, 4}; // 注意:这种情况是非法的,编译报错
[……]