type
status
date
slug
summary
tags
category
icon
password
Property
JavaScript的默认对象表示方式
{}
可以视为其他语言中的Map
或Dictionary
的数据结构,即一组键值对。但是JavaScript的对象有个小问题,就是键必须是字符串。但实际上Number或者其他数据类型作为键也是非常合理的。
Map
Map
是一组键值对的结构,具有极快的查找速度。举个例子,假设要根据同学的名字查找对应的成绩,如果用
Array
实现,需要两个Array
:给定一个名字,要查找对应的成绩,就先要在names中找到对应的位置,再从scores取出对应的成绩,Array越长,耗时越长。
如果用Map实现,只需要一个“名字”-“成绩”的对照表,直接根据名字查找成绩,无论这个表有多大,查找速度都不会变慢。用JavaScript写一个Map如下:
初始化
Map
需要一个二维数组,或者直接初始化一个空Map
。Map
具有以下方法:🦛
type
status
date
slug
summary
tags
category
icon
password
Property
在Java程序中,
synchronized
解决了多线程竞争的问题。例如,对于一个任务管理器,多个线程同时往队列中添加任务,可以用synchronized
加锁:上述代码看上去没有问题:
getTask()
内部先判断队列是否为空,如果为空,就循环等待,直到另一个线程往队列中放入了一个任务,while()
循环退出,就可以返回队列的元素了。但实际上
while()
循环永远不会退出。因为线程在执行while()
循环时,已经在getTask()
入口获取了this
锁,其他线程根本无法调用addTask()
,因为addTask()
执行条件也是获取this
锁。因此,执行上述代码,线程会在
getTask()
中因为死循环而100%占用CPU资源。如果深入思考一下,我们想要的执行效果是:
- 线程1可以调用
addTask()
不断往队列中添加任务;
- 线程2可以调用
getTask()
从队列中获取任务。如果队列为空,则getTask()
应该等待,直到队列中至少有一个任务时再返回。
因此,多线程协调运行的原则就是:当条件不满足时,线程进入等待状态;当条件满足时,线程被唤醒,继续执行任务。
对于上述
TaskQueue
,我们先改造getTask()
方法,在条件不满足时,线程进入等待状态:type
status
date
slug
summary
tags
category
icon
password
Property
行间事件
JS是一门事件驱动型的编程语言,依靠事件去驱动,然后执行对应的程序。
在JS中有很多事件,其中有一个事件叫做:鼠标单击(click)。并且任何事件都会对应一个事件句柄叫做:onclick。
事件和事件句柄的区别是:事件句柄是在事件单词前添加一个on,而事件句柄是以HTML标签的属性存在的
onclick="js代码",执行原理是什么?
页面打开的时候,js代码并不会执行,只是把这段JS代码注册到按钮的click事件上了。等这个按钮发生click事件之后,注册在onclick后面的js代码会被浏览器自动调用。
怎么使用JS代码弹出消息框?
在JS中有一个内置的对象叫做window,全部小写,可以直接拿来使用,window代表的是浏览器对象
window对象有一个函数叫做:alert,用法是:window.alert("消息");这样就可以弹窗了
🦛
type
status
date
slug
summary
tags
category
icon
password
Property
如果线程需要执行一个长时间任务,就可能需要能中断线程。中断线程就是其他线程给该线程发一个信号,该线程收到信号后结束执行
run()
方法,使得自身线程能立刻结束运行。假设从网络下载一个100M的文件,如果网速很慢,用户等得不耐烦,就可能在下载过程中点“取消”,这时,程序就需要中断下载线程的执行。
中断一个线程非常简单,只需要在其他线程中对目标线程调用
interrupt()
方法,目标线程需要反复检测自身状态是否是interrupted状态,如果是,就立刻结束运行。仔细看上述代码,
main
线程通过调用t.interrupt()
方法中断t
线程,但是要注意,interrupt()
方法仅仅向t
线程发出了“中断请求”,至于t
线程是否能立刻响应,要看具体代码。而t
线程的while
循环会检测isInterrupted()
,所以上述代码能正确响应interrupt()
请求,使得自身立刻结束运行run()
方法。如果线程处于等待状态,例如,
t.join()
会让main
线程进入等待状态,此时,如果对main
线程调用interrupt()
,join()
方法会立刻抛出InterruptedException
,因此,目标线程只要捕获到join()
方法抛出的InterruptedException
,就说明有其他线程对其调用了interrupt()
方法,通常情况下该线程应该立刻结束运行。main
线程通过调用t.interrupt()
从而通知t
线程中断,而此时t
线程正位于hello.join()
的等待中,此方法会立刻结束等待并抛出InterruptedException
。由于我们在t
线程中捕获了InterruptedException
,因此,就可以准备结束该线程。在t
线程结束前,对hello
线程也进行了interrupt()
调用通知其中断。如果去掉这一行代码,可以发现hello
线程仍然会继续运行,且JVM不会退出。另一个常用的中断线程的方法是设置标志位。我们通常会用一个
running
标志位来标识线程是否应该继续运行,在外部线程中,通过把HelloThread.running
置为false
,就可以让线程结束:注意到
HelloThread
的标志位boolean running
是一个线程间共享的变量。线程间共享变量需要使用volatile
关键字标记,确保每个线程都能读取到更新后的变量值。🦛
type
status
date
slug
summary
tags
category
icon
password
Property
ReentrantLock
保证了只有一个线程可以执行临界区代码:但是有些时候,这种保护有点过头。因为我们发现,任何时刻,只允许一个线程修改,也就是调用
inc()
方法是必须获取锁,但是,get()
方法只读取数据,不修改数据,它实际上允许多个线程同时调用。实际上我们想要的是:允许多个线程同时读,但只要有一个线程在写,其他线程就必须等待:
使用
ReadWriteLock
可以解决这个问题,它保证:- 只允许一个线程写入(其他线程既不能写入也不能读取);
- 没有写入时,多个线程允许同时读(提高性能)。
用
ReadWriteLock
实现这个功能十分容易。我们需要创建一个ReadWriteLock
实例,然后分别获取读锁和写锁:把读写操作分别用读锁和写锁来加锁,在读取时,多个线程可以同时获得读锁,这样就大大提高了并发读的执行效率。
🦥
type
status
date
slug
summary
tags
category
icon
password
Property
从Java 7开始,提供了
Files
和Paths
这两个工具类,能极大地方便我们读写文件。虽然
Files
和Paths
是java.nio
包里面的类,但他俩封装了很多读写文件的简单方法,例如,要把一个文件的全部内容读取为一个byte[]
,可以这么写:如果是文本文件,可以把一个文件的全部内容读取为
String
:写入文件也非常方便:
此外,
Files
工具类还有copy()
、delete()
、exists()
、move()
等快捷方法操作文件和目录。最后需要特别注意的是,
Files
提供的读写方法,受内存限制,只能读写小文件,例如配置文件等,不可一次读入几个G的大文件。读写大型文件仍然要使用文件流,每次只读写一部分文件内容。🦥
type
status
date
slug
summary
tags
category
icon
password
Property
IO是指Input/Output,即输入和输出。以内存为中心:
- Input指从外部读入数据到内存,例如,把文件从磁盘读取到内存,从网络读取数据到内存等等。
- Output指把数据从内存输出到外部,例如,把数据从内存写入到文件,把数据从内存输出到网络等等。
从Java代码来看,输入实际上就是从外部,例如,硬盘上的某个文件,把内容读到内存,并且以Java提供的某种数据类型表示,例如,
byte[]
,String
,这样,后续代码才能处理这些数据。因为内存有“易失性”的特点,所以必须把处理后的数据以某种方式输出,例如,写入到文件。Output实际上就是把Java表示的数据格式,例如,
byte[]
,String
等输出到某个地方。IO流是一种顺序读写数据的模式,它的特点是单向流动。数据类似自来水一样在水管中流动,所以我们把它称为IO流。
InputStream / OutputStream
IO流以
byte
(字节)为最小单位,因此也称为字节流。例如从磁盘读入一个文件,包含6个字节,就相当于读入了6个字节的数据:🐼
type
status
date
slug
summary
tags
category
icon
password
Property
注意Collections结尾多了一个s,不是Collection!
Collections
是JDK提供的工具类,同样位于java.util
包中。它提供了一系列静态方法,能更方便地操作各种集合一般看方法名和参数就可以确认
Collections
提供的该方法的功能。例如,对于以下静态方法:addAll()
方法可以给一个Collection
类型的集合添加若干元素。因为方法签名是Collection
,所以可以传入List
,Set
等各种集合类型。创建空集合
Collections
提供了一系列方法来创建空集合:- 创建空List:
List<T> emptyList()
- 创建空Map:
Map<K, V> emptyMap()
- 创建空Set:
Set<T> emptySet()