龙空技术网

JAVA 操作笔记(四)

盒你一起去月球 126

前言:

此时姐妹们对“java登录接口无法从套接字读取更多数据”大概比较关切,看官们都想要学习一些“java登录接口无法从套接字读取更多数据”的相关知识。那么小编也在网上收集了一些关于“java登录接口无法从套接字读取更多数据””的相关内容,希望我们能喜欢,各位老铁们一起来学习一下吧!

装饰模式

动态的给一个对象添加额外的职责。在不改变原对象的前提下,额外的添加一些逻辑。Spring AOP就是这样发展来的。

将对象序列化与反序列化操作的流

OIS与OOS

ObjectInputStream

ObjectOutputStream

若我们的对象想被序列化,需要实现序列化接口

Serializable接口。表示其子类是可以序列化的。

序列化对象的作用:

1: 该对象保存着的数据需要一直使用,我们可以将其序列化后写入硬盘做长久保存,这样,下次程序启动后我们还可以将其读取回来继续使用。

2: 将对象进行网络传输。

JDK中大部分类都实现了序列化接口。例如ArrayList都实现了。也就是说他们都可以被序列化。

反序列化后的对象,和原对象equals比较为true.但是他们不是一个对象,且若属性也是引用类型,那么这些属性也都不是同一个对象,但equals比较也为true。

深度复制对象需要先将对象序列化再反序列化。

这就需要我们使用ObjectOutputStream和ObjectInputStream

但这两个流需要将数据写出和读入,我们不希望在复制过程中先将对象写到磁盘上再读回来,因为这样太慢!

我们既要使用oos和ois又要在内存中完成序列化与反序列化操作。

ByteArrayInputStream ByteArrayOutputStream

这两个流也有明确的来源和去向,这两个流内部维护着一个字节数组。

我们通过ByteArrayOutputStream写出的字节,就是写到了其内部维护的字节数组上了。

通过ByteArrayInputStream读取数据实际上就是将其内部的字节数组中的字节读取出来。

多线程

多线程:使计算机的操作系统可以在同一时刻执行多个任务

操作系统级别的任务就是一个应用程序。每个任务又成为一个进程。

对于一个程序而言,也可能同时运行多个任务,那么每个任务成为一个线程。

并发:进程或线程是并发运行的。OS将时间分成若干段,并分配给每个进程或线程,得到时间片段的进程或线程将得到cpu的执行。所以,微观上进程或线程是走走停停的。宏观上是同时在执行。这种现象称为并发。

线程运行机制:

当我们调用线程的 start()方法时,该 线程会向线程调度注册当前线程。只有注册了,才有机会被分配时间片进行并发运行。

不要去调用run方法。若直接调用run()方法那么就不是并发运行了,而是变成同步运行了。有先后顺序的执行。

时间片段是不均匀的。每个线程分配的时间不是相等的。线程调度机制尽可能均匀的将时间片段分配给不同线程,让他们都有机会得到cpu的运行。对于线程调度机制而言,我们的程序对具体将时间片段分配给那个线程是不可控的。

葛大爷拍戏是典型的多线程并发运

行。

葛大爷是cpu。

秘书是线程调度机制。

赵氏孤儿,非诚勿扰2,让子弹飞这三个剧组就是三个需要并发的线程。

档期就是时间片段。

内部类

静态内部类

public class A{

public int a;

public static class B{

public void say(){

a++;//不行

}

}

}

静态内部类不能直接引用外部类的非静态属性和方法。

实例化静态内部类

A.B b = new A.B();

非静态内部类

public class A{

private int a = 0;

public class B{

public void say(){

a++;//可以

}

}

}

非静态内部类中可以引用外部类的属性和方法

A a = new A();

B b = a.new B();

线程的启动和关闭

start(): 线程的启动方法。若想让run()方法中的代码并发执行,我们需要调用start方法

stop(): 关闭线程的方法。该方法不建议使用,具有 不安全性。停止线程的正确方式应该是让 run方法正常执行完毕。

线程运行过程中若出现类未捕获的异常,该线程会立刻终止。但是不会影响当前进程中其他线程的工作

若当前进程中所有线程都终止了,那么进程终止。

当我们的程序启动时,操作系统分配一个进程来运行我们的程序,而该进程会创建一个线程来调用我们的main方法。

创建线程的另一种方式。

将线程与线程体分开

所谓线程体就是线程要并发执行的逻辑。

最好的模式应该是线程只关心并发操作,不关心具体并发做的事情。我们应将线程体与线程本身解耦。

解耦: 解除依赖关系,自己关心自己的事情。不决定自己不该关心的内容。

单独定义线程体

Runnable接口

该接口用于描述可执行的逻辑,一般描述的就是线程体。

线程进入死亡状态后,不要再调用start()方法。

与线程声明周期相关的方法

static void yield():

主动放弃当次时间片段,进入runnable状态,等待下次分配时间片。主动离开running状态

static void sleep(long time):

从running状态主动进入 block状态

阻塞time毫秒后自动回到runnable状态

若在阻塞过程中被打断睡眠阻塞会引发异常InterruptException

void interrupt():

中断线程

线程的优先级

线程优先级高的线程,被分配时间片段的几率高,换句话说被cpu执行的次数多。

注意,这不是绝对的。但是大多数情况下是这样的。毕竟线程调度分配时间片段是不可控的。

守护线程

守护线程又叫后台线程

守护线程的特点,当进程中所有前台线程都终止后,守护线程强制终。当进程中只剩下后台线程时,进程终止。

后台线程是在线程启动前通过方法设置的。

setDaemon(boolean on)

当参数为true时,该线程为后台线程。

设置 后台线程必须在线程调用start()方法之前进行!

线程安全问题

当多线程共享同一数据时,就可能引发线程安全问题。

synchronized关键字

synchronized可以 修饰方法,也可以独立以 代码块的形式存在

若修饰方法,那么该方法就是同步方法,多线程不能同时访问该方法。

synchronized若修饰方法,那么当一个线程进入该方法后,会对当前方法所属的对象加锁。那么其他线程在访问该对象的这个方法时,发现该对象被锁上了,那么就在方法外等待,直到对象上的锁被释放掉为止。

StringBuffer和StringBuilder

用法一样。 StringBuffer是线程安全的。

List集合

Vector是线程安全的集合

ArrayList不是线程安全的

Map

HashMap不是线程安全的

HashTable是线程安全的

Collections 有获取 线程安全的集合的方法

Collections.synchronizedList()

获取一个线程安全的List集合

List list = Collections.synchronizedList()

获取线程安全的Map

Collections.synchronizedMap()

获取线程安全的Set

Collections.synchronizedSet()

wait 与 notify

这两个方法不是在Thread中定义的。而是在Object中定义的。

当线程A调用了B对象wait方法,那么该线程就在B对象上等待。A线程进入wait阻塞。

当线程C调用了B对象wait方法,那么该线程也在B对象上等待。

当B对象调用了notify方法,那么A或B随机一个进入Runnable状态开始运行,另一个仍然处于wait阻塞。

notifyAll方法可以让在当前对象上等待的所有线程进入runnable状态。

java网络编程(Socket编程 )

Socket 套接字:封装着如端口号,ip地址,计算机名等信息的类。

通过Socket我们可以与远程计算机通信。

网络通信模型

C/S:client/server

客户端对服务器端

客户端通常运行在用户的计算机上,客户端是一个特有的程序,实现特有的功能,用于连接服务器端进行通信。

谁发起连接谁是用户。

服务器端程序通常是等待客户端连接,提供功能服务并与之通信。

通信协议: 计算机通信的实质就是相互收发字节。那么按照一定的格式收发字节就是通信协议。

B/S结构:

浏览器端对服务器端。

固定了客户端和通信协议的C/S结构

线程池

频繁的创建线程和销毁线程是非常消耗资源和性能的。

创建一些空的线程。将他们保存起来,当有任务需要并发执行时,我们取出一个空闲的线程来运行这个任务,当任务运行完毕后,在将线程回收,等待下次分配任务。

这样,自始至终我们都只创建了开始创建的那些线程,并可以重复利用来节省性能开销。

ExecutorService

线程池实现

通过Executors类的静态方法创建几个不同实现的线程池

Executors.newCachedThreadPool()

创建一个线程池,当有任务的时候会检查线程池中是否有空线程,若有就是用它,若没有就创建新的线程。

Executors.newFixedThreadPool(int threads)

创建一个具有 固定大小的线程池。

Executors.newScheduledThreadPool(int threads)

创建一个线程池,他可以安排任务在指定 延时后并发执行或定期执行

Executors.newSingleThreadExceutor()

创建一个 单线程的线程池。该池中维护一个任务队列,以单线程方式执行队列中的每一个任务。

双端队列

内部由两个队列实现,他们交替进行存取工作。这样至少可以保证2个线程可以同时进行存取操作。

但是对于两个线程同时进行存或者同时进行取操作,还是要求同步的。

但是比单队列实现线程安全还是要快的。

BlockingDeque双端队列

实现:

ArrayBlockingDeque 该类实现的构造方法要求我们传入一个整数,代表当前队列的长度。所以这个是一个固定大小的双端队列,存取原则为FIFO 先入先出原则

当元素调用offer存入队列时,若队列已满,那么可以设置延时等待,当超过了延时等待会返回存入失败。

LinkedBlockingDeque 变长双端队列。长度不定,随着元素数量而增大,最大可达Integer.MAX_VALUE

重载构造方法可以传入一个整数,使之变为一个定长的队列。存取原则FIFO first input first output

PriorityBlockingDeque

和 LinkedBlockingDeque 类似。但存取不是FIFO而是经过自然排序后获取

SynchronousQueue 特殊的双端队列,存取步骤有要求,必须存一次取一次,交替进行。

标签: #java登录接口无法从套接字读取更多数据