线程:(续)
juc中的大部分类是通过无锁并发实现的(没有用synchronized)
CAS机制compare And Swap比较并交换
synchronized可以称之为悲观锁
cas体现的是乐观锁
首先不会给共享资源加锁,而是做一个尝试,先拿到旧值,查看旧值是否跟共享区域的值相等,如果不等,那么说明
别的线程改动了共享区域的值,我的修改失败了,如果相等,那么就让我的修改成功,(如果我们修改失败,没有关系,重新尝试)然后别人就不能修改
```java
int var5;
// 修改失败,没关系,重新尝试 自旋
do {
// 获取共享区域的最新值
var5 = this.getIntVolatile(var1, var2); // 10
// 比较并交换 最新值 最新值+1
} while(! this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
```
重入锁:ReentrantLock
.lock():加锁
.unlock():解锁
public class ReentrantLockDemo {
static int a=0;
public static void main(String[] args) throws InterruptedException {
ReentrantLock lock=new ReentrantLock();
Thread thread = new Thread(() -> {
for (int j = 0; j <500 ; j++) {
try{
lock.lock();
a++;
}finally{
lock.unlock();
}
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 500; i++) {
try {
lock.lock();
a--;
} finally {
lock.unlock();
}
}
});
thread.start();
thread2.start();
thread.join();
thread2.join();
System.out.println(a);
}
}
synchronized性能上比较ReentrantLock在高并发下低,ReentrantLock的内存占用会高一些
CountDownLatch:
countDown倒计时
就是说当希望多个线程执行完毕之后,再接着做下一步操作时,
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownlatch=new CountDownLatch(2);
new Thread(()->{
System.out.println("线程1准备开始了...."+new Date());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1马上结束了...."+new Date());
countDownlatch.countDown();
}).start();
new Thread(()->{
System.out.println("线程2准备开始了..."+new Date());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2马上结束了..."+new Date());
countDownlatch.countDown();
}).start();
System.out.println("主线程等待中....."+new Date());
countDownlatch.await();
System.out.println("主线程马上结束..."+new Date());
}
}
一个应用例子:模拟10个玩家加载进度
```java
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(10);
String[] all = new String[10];
for (int j = 0; j < 10; j++) {
int x = j;
new Thread(()->{
Random r = new Random();
for (int i = 0; i <= 100; i++) {
try {
Thread.sleep(r.nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (all){
all[x]=(i+"%");
System.out.print("\r"+Arrays.toString(all));
}
}
latch.countDown();
}).start();
}
latch.await();
System.out.println("\nend...");
}
```
循环栅栏:
CyclicBarrier 可循环的屏障(栅栏)
当满足CyclicBarrier设置的线程个数时,继续执行,没有满足则等待
public class CyclieBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
new Thread(()->{
System.out.println("线程1准备执行..."+new Date());
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("线程1执行完毕....."+new Date());
}).start();
new Thread(()->{
System.out.println("线程2准备执行....."+new Date());
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("线程2执行结束....."+new Date());
}).start();
}
}
与 倒计时锁的区别:倒计时锁只能使用一次,倒计时结束这个对象就没有用了,而循环栅栏可以重复利用
信号量:
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore=new Semaphore(2);
for (int i = 0; i <10 ; i++) {
new Thread(()->{
try {
semaphore.acquire();
try {
System.out.println("我是线程"+Thread.currentThread().getName());
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
}
}).start();
}
}
}
2.网络模型与协议
OSI七层模式:
应用层,表示层,会话层,传输层,网络层,链路层,物理层
五层模式:
应用层,传输层,网络层,链路层,物理层
四层模式:
应用层,传输层,网络层,链路层
应用层:http(超文本传输协议)ftp(文件传输协议)stmp(邮件发送协议)pop3(邮件接收协议),ssh(安全shell,用于远程登录)
传输层: tcp(安全可靠的协议)udp(不可靠的协议)
网络层:ip
Windows下可以使用ipconfig来查看IP地址
Linux下可以使用ifconfig来查看
ip地址的作用是用来定位到网络上的另一台计算机
port 端口
mysql 3306
oracle 1521
sqlserver 1433
redis 6379
tomcat 8080
apache(http的服务) 80
ftp 21
ssh 22
端口号的作用是用来标记,要访问对方的哪个程序
传输层协议:
tcp协议:
TCP协议的特点是:TCP协议是一个有连接、可靠的协议。所谓有连接指的是进行TCP通信之前,两个需要通信的主机之间首先简历一条数据通道,就好像打电话进行交流之前首先要让电话接通一样。所谓可靠,指的是TCP协议能够保证:1、发送端发送的数据不会丢失,2、接收端接收的数据包的顺序,会按照发送端发送的包的顺序接收。也就是说,TCP协议能够保证数据能够完整无误的传输。
udp:
与TCP协议相比,UDP是一个无连接不可靠的协议,即:数据的发送方只负责将数据发送出去,数据的接收方只负责接收数据。发送方和接收方不会相互确认数据的传输是否成功。相对于TCP而言,UDP有一个优点:效率较高。因此,当我们在对数据传输的正确率不太关心,但是对传输率要求较高的情况下,可以采用UDP协议。典型的使用UDP协议是网络语音以及视频聊天应用
Java中的网络编程
SocketAPI对tcp、udp协议做了封装,能够连接到对方主机,收发数据
tcp的例子:建立连接服务器端:
服务器端:
public static void main(String[] args) throws IOException {
// 可以与客户端的socket建立连接 端口号一般使用4位以上的数字
ServerSocket ss = new ServerSocket(5555);
System.out.println("ready...等待客户端连接");
// 端点
Socket socket = ss.accept();// 等待客户端连接我服务器方法,直到有客户端连接
}
客户端:
public static void main(String[] args) throws IOException {
// 本机ip地址为 127.0.0.1
// 它的别名 localhost
// 端点
Socket socket =
new Socket("127.0.0.1", 5555);
}