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 特殊的双端队列,存取步骤有要求,必须存一次取一次,交替进行。

相关文章
|
21天前
|
Java 开发工具 Android开发
Kotlin语法笔记(26) -Kotlin 与 Java 共存(1)
本系列教程笔记详细讲解了Kotlin语法,适合需要深入了解Kotlin的开发者。若需快速学习Kotlin,建议查看“简洁”系列教程。本期重点介绍了Kotlin与Java的共存方式,包括属性、单例对象、默认参数方法、包方法、扩展方法以及内部类和成员的互操作性。通过这些内容,帮助你在项目中更好地结合使用这两种语言。
38 1
|
22天前
|
Java 开发工具 Android开发
Kotlin语法笔记(26) -Kotlin 与 Java 共存(1)
Kotlin语法笔记(26) -Kotlin 与 Java 共存(1)
30 2
|
1月前
|
Java 开发工具 Android开发
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
|
12天前
|
安全 Java 编译器
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
|
12天前
|
Java 开发工具 Android开发
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
|
12天前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
Kotlin教程笔记(28) -Kotlin 与 Java 混编
|
21天前
|
Java 编译器 Android开发
Kotlin语法笔记(28) -Kotlin 与 Java 混编
本系列教程详细讲解了Kotlin语法,适合需要深入了解Kotlin的开发者。对于希望快速学习Kotlin的用户,推荐查看“简洁”系列教程。本文档重点介绍了Kotlin与Java混编的技巧,包括代码转换、类调用、ProGuard问题、Android library开发建议以及在Kotlin和Java之间互相调用的方法。
18 1
|
21天前
|
安全 Java 编译器
Kotlin语法笔记(27) -Kotlin 与 Java 共存(二)
本教程详细讲解Kotlin语法,适合希望深入了解Kotlin的开发者。若需快速入门,建议查阅“简洁”系列教程。本文重点探讨Kotlin与Java共存的高级话题,包括属性访问、空安全、泛型处理、同步机制及SAM转换等,助你在项目中逐步引入Kotlin。
18 1
|
22天前
|
Java 编译器 Android开发
Kotlin语法笔记(28) -Kotlin 与 Java 混编
Kotlin语法笔记(28) -Kotlin 与 Java 混编
24 2
|
28天前
|
Java 数据库连接 编译器
Kotlin教程笔记(29) -Kotlin 兼容 Java 遇到的最大的“坑”
Kotlin教程笔记(29) -Kotlin 兼容 Java 遇到的最大的“坑”