1. 散列表核心类
Vector——线程安全,ArrayList——线程不安全
Hashtable——线程安全,HashMap——线程不安全
· Vector
Vector类中的方法(除构造方法)都是线程安全的,故在要求线程安全的场合下调用Vector类的下列方法,不需要考虑线程安全的问题,如:
或,
上面的代码主动为Vector对象添加了线程同步的约束语句来同步多线程环境,其实是多余的,只会降低系统性能,因为Vector对象本身就是线程安全的。修正上述代码:
在多线程环境下使用Vector类十分简洁、安全。但在某些场景中,线程并不需要写(更新)共享资源数据,而仅仅是读取、使用,此时开发人员就不需要考虑多线程的同步问题。
同步方法的意义:
防止多线程的运行环境里,两个或多个线程同时访问受保护的资源,而导致资源数据不完整,破坏数据资源,程序无法达到预期目的。
· ArrayList
ArrayList类中的方法是非线程安全的,尽管如此,在多线程环境下要求线程安全,也可以使用ArrayList等非线程安全的散列表核心类,可以通过下面的方法:
通过这个方法可将ArrayList标识为线程安全(thread-safe)的对象。
在合适的场合,建议尽量使用ArrayList,而不建议使用Vector。
与LinkedList比较:
ArrayList是通过内部数组结构Object[]实现的,而LinkedList通过将一系列的内部记录连接在一起实现的。即ArrayList对象持有的数据是顺序存储,而LinkedList对象则是链式存储。
String类
String可以存储16位的Unicode字符序列及其长度,一旦被创建,这个字符串就是恒定不变。
字符串累加
下面的代码:
类似于下面的代码:
以上代码的意思:将两个字符串串联后拷贝到一个临时字符串缓冲区变量中,如果这个被拷贝的字符串较长,那么这个拷贝操作就非常耗费资源。
有2种方式可提高字符串累加的性能:
1) 通过StringBuffer来构建一个字符串对象
例:
修改为:
2) 通过char[]数组
先创建一个字符数组,然后向其中添加字符,达到累加的目的,返回最终生成的字符串。
遍历字符
若字符串特别长,又需要逐一获取字符串特定位置的字符,则通过调用toCharArray()转化为字符串数组,再由数组索引值获取指定位置的字符,而不是直接调用charAt(int index)。
例:
3. 系统I/O类
Java中输入、输出流种类繁多,但按照它们所处理的数据流的类型可将其分为两类:二进制数据输入/输出流(处理二进制数据,),与字符数据输入/输出流(处理字符数据)。InputStream与OutputStream是用来处理二进制数据流的高层接口,Reader与Writer是用来处理字符数据的高层接口。
Java中一般的输入与输出流类都是采用单字节的读取方法,进行数据I/O操作的,即每次只读取或写入一个字节的数据,这种方法显然烦琐低效。
单字节读取/写入过程
1) 通过系统缓冲流类提高I/O操作效率
采用数据缓冲类读取/写入过程
例:
可修改上面的代码改用系统缓冲流类来提高I/O效率:
2) 通过自定义缓冲区提高I/O操作效率
例:
不是数据缓冲越大,系统性能就越高,缓冲区的大小应该根据实际情况定义一个合理的值(最好是512的倍数,这样运算速度要快一些)。通常情况下需要权衡两个方面的因素:
a) 读取与写入的文件的大小
b) 应用运行的硬件环境的内存资源
总之,得到下面的结论:
· 采用默认的数据输入/输出方式(直接读取与写入)将导致系统性能下降
· 采用系统数据缓冲流类读取与写入数据,将提升系统性能
· 采用自定义合理缓冲区读取与写入数据,将更大程度地提升系统性能
3) 通过压缩流提供I/O操作效率
java.util.zip包存在ZipInputStream与ZipOutputStream,可通过它们实现压缩流的读取与写入。
例:
除了在文件读写方面可以采用压缩流提高系统性能外,在网络数据传输中也可以通过压缩流节省网络资源,提高传输效率。
4) 通过非阻塞I/O优化应用性能
JDK1.4中退出的java.nio(新输入/输出)软件包,NIO包设计更清晰、简单、高效,能帮助开发者在数据处理时取得更强的性能及更佳的扩展性。
在NIO包中引入了四个关键的抽象数据类型,它们共同解决传统的I/O类中的一些问题。
a) Buffer:包含数据且用于读写的线性表结构。其中还提供了一个特殊类用于内存映射文件的I/O操作
b) Charset:提供Unicode字符串映射到字节序列以及逆映射的操作
c) Channel:包含socket、file和pipe三种管道,它实际上是双向交流的通道
d) Selector:它将多元异步I/O操作集中到一个或多个线程中(它可被看成UNIX中select()或Win32中WaitForSingleEvent()的面向对象版本)
NIO API引入一种称为通道的新型原始I/O提取方法。通道表示到实体(如硬件设备、文件、网络套接字或可执行一个或多个诸如读写I/O操作的程序组件)的开放连接。通道可以处于打开或关闭状态,既是可异步关闭的,又是可中断的。
有几个接口对Channel接口进行了扩展,每个接口指定一个新的I/O操作。以下是其中几个接口的信息:
ReadableByteChannel指定一个将字节从通道读入缓冲器的read()
WritableByteChannel指定一个将字节从通道写入缓冲器的write()
ScatteringByteChannel和GatheringByteChannel分别扩展ReadableByteChannel和WritableByteChannel,采用缓冲器序列而非一个单独缓冲器增加read()和write()
FileChannel支持从连接到文件的通道读取字节或向其写入字节,及查询和修改当前的文件位置和将文件调整为指定大小等常见操作
使用FileChannel读写文件,例:
使用FileChannel读取文本文件内容,例:
非阻塞操作是NIO最常见与最广泛应用的功能。需要调用SelectableChannel中的configureBlocking()方法配置阻塞或非阻塞操作(在阻塞方式下调用读、写或其他操作,直到操作完成才能返回)。
非阻塞I/O最为显著的性能优势包括:
· 可以进行非阻塞异步输入/输出
· 能锁定整个或部分文件
在非阻塞方式下,SelectableChannel对象通过register()向Selector对象注册,然后签署特殊事件。在指定操作发生时,Selector对象就会发出通知。这些事件由SelectionKey的域反映。
例:
在connect()后,它将立即返回执行情况。然后,你必须指出如何处理这样的通道连接,这时有:
在收到通知后,又有:
Vector——线程安全,ArrayList——线程不安全
Hashtable——线程安全,HashMap——线程不安全
· Vector
Vector类中的方法(除构造方法)都是线程安全的,故在要求线程安全的场合下调用Vector类的下列方法,不需要考虑线程安全的问题,如:
public synchronized void addObj2Vector(Object obj) { vector.addElement(obj); }
或,
public void addObj2Vector(Object obj) { synchronized { vector.addElement(obj); } }
上面的代码主动为Vector对象添加了线程同步的约束语句来同步多线程环境,其实是多余的,只会降低系统性能,因为Vector对象本身就是线程安全的。修正上述代码:
public void addObj2Vector(Object obj) { vector.addElement(obj); }
在多线程环境下使用Vector类十分简洁、安全。但在某些场景中,线程并不需要写(更新)共享资源数据,而仅仅是读取、使用,此时开发人员就不需要考虑多线程的同步问题。
同步方法的意义:
防止多线程的运行环境里,两个或多个线程同时访问受保护的资源,而导致资源数据不完整,破坏数据资源,程序无法达到预期目的。
· ArrayList
ArrayList类中的方法是非线程安全的,尽管如此,在多线程环境下要求线程安全,也可以使用ArrayList等非线程安全的散列表核心类,可以通过下面的方法:
List list = Collections.synchronizedList(new ArrayList());
通过这个方法可将ArrayList标识为线程安全(thread-safe)的对象。
在合适的场合,建议尽量使用ArrayList,而不建议使用Vector。
与LinkedList比较:
ArrayList是通过内部数组结构Object[]实现的,而LinkedList通过将一系列的内部记录连接在一起实现的。即ArrayList对象持有的数据是顺序存储,而LinkedList对象则是链式存储。
String类
String可以存储16位的Unicode字符序列及其长度,一旦被创建,这个字符串就是恒定不变。
字符串累加
下面的代码:
String s = "first string"; s = s + “second string”;
类似于下面的代码:
String s = "first string"; StringBuffer tmp = new StringBuffer(s); tmp.append("second string"); s = tmp.toString();
以上代码的意思:将两个字符串串联后拷贝到一个临时字符串缓冲区变量中,如果这个被拷贝的字符串较长,那么这个拷贝操作就非常耗费资源。
有2种方式可提高字符串累加的性能:
1) 通过StringBuffer来构建一个字符串对象
例:
String s = ""; for (int i = 1; i <= N; i++) { s = s + "*"; }
修改为:
StringBuffer sb = new StringBuffer(); for (int i = 1; i <= N; i++) { sb.append("*"); } String s = sb.toString();
2) 通过char[]数组
先创建一个字符数组,然后向其中添加字符,达到累加的目的,返回最终生成的字符串。
遍历字符
若字符串特别长,又需要逐一获取字符串特定位置的字符,则通过调用toCharArray()转化为字符串数组,再由数组索引值获取指定位置的字符,而不是直接调用charAt(int index)。
例:
... char[] ss = s.toCharArray(); for (int i = 0; i < ss.length; i++) { char c = ss[i]; ... } ...
3. 系统I/O类
Java中输入、输出流种类繁多,但按照它们所处理的数据流的类型可将其分为两类:二进制数据输入/输出流(处理二进制数据,),与字符数据输入/输出流(处理字符数据)。InputStream与OutputStream是用来处理二进制数据流的高层接口,Reader与Writer是用来处理字符数据的高层接口。
Java中一般的输入与输出流类都是采用单字节的读取方法,进行数据I/O操作的,即每次只读取或写入一个字节的数据,这种方法显然烦琐低效。
单字节读取/写入过程
1) 通过系统缓冲流类提高I/O操作效率
采用数据缓冲类读取/写入过程
例:
InputStream is = null; OutputStream os = null; try { is = new FileInputStream(fileFrom); os = new FileInputStream(fileTo); while (true) { int bytedata = is.read(); if (bytedata == -1) { break; } os.write(bytedata); } } catch (Exception e) { ... } finally { if (is != null) { is.close(); } if (os != null) { os.close(); } }
可修改上面的代码改用系统缓冲流类来提高I/O效率:
InputStream is = null; OutputStream os = null; try { is = new BufferedInputStream(new FileInputStream(fileFrom)); os = new BufferedInputStream(new FileInputStream(fileTo)); while (true) { int bytedata = is.read(); if (bytedata == -1) { break; } os.write(bytedata); } } catch (Exception e) { ... } finally { if (is != null) { is.close(); } if (os != null) { os.close(); } }
2) 通过自定义缓冲区提高I/O操作效率
例:
InputStream is = null; OutputStream is = null; try { is = new FileInputStream(fileFrom); os = new FileInputStream(fileTo); byte[] totalBytes = new byte[is.available()]; is.read(totalBytes); os.write(totalBytes); } catch (Exception e) { ... } finally { if (is != null) { is.close(); } if (os != null) { os.close(); } }
不是数据缓冲越大,系统性能就越高,缓冲区的大小应该根据实际情况定义一个合理的值(最好是512的倍数,这样运算速度要快一些)。通常情况下需要权衡两个方面的因素:
a) 读取与写入的文件的大小
b) 应用运行的硬件环境的内存资源
总之,得到下面的结论:
· 采用默认的数据输入/输出方式(直接读取与写入)将导致系统性能下降
· 采用系统数据缓冲流类读取与写入数据,将提升系统性能
· 采用自定义合理缓冲区读取与写入数据,将更大程度地提升系统性能
3) 通过压缩流提供I/O操作效率
java.util.zip包存在ZipInputStream与ZipOutputStream,可通过它们实现压缩流的读取与写入。
例:
public void zip(String fileFrom, String fileTo) throws IOException { ZipOutputSream zos = new ZipOutputSream(new FileOutputStream(fileTo)); zos.putNextEntry(new ZipEntry(fileTo)); FileInputStream fis = new FileInputStream(fileFrom); byte[] buf = new byte[1024]; int n; while ((n = fis.read(buf)) > -1) { zos.write(buf, 0, n); } buf = null; fis.close(); fis = null; zos.flush(); zos.closeEntry(); zos.close(); zos = null; } public void upzip(String fileFrom, String fileTo) throws IOException { ZipInputStream zis = new ZipInputStream(new FileInputStream(fileFrom)); if (zis.getNextEntry() != null) { FileOutputStream fos = new FileOutputStream(fileTo); int n; byte[] buf = new byte[1024]; while ((n = zis.read(buf)) > -1) { fos.write(buf, 0, n); } buf = null; fos.flush(); fos.close(); fos = null; } zis.closeEntry(); zis.close(); zis = null; }
除了在文件读写方面可以采用压缩流提高系统性能外,在网络数据传输中也可以通过压缩流节省网络资源,提高传输效率。
4) 通过非阻塞I/O优化应用性能
JDK1.4中退出的java.nio(新输入/输出)软件包,NIO包设计更清晰、简单、高效,能帮助开发者在数据处理时取得更强的性能及更佳的扩展性。
在NIO包中引入了四个关键的抽象数据类型,它们共同解决传统的I/O类中的一些问题。
a) Buffer:包含数据且用于读写的线性表结构。其中还提供了一个特殊类用于内存映射文件的I/O操作
b) Charset:提供Unicode字符串映射到字节序列以及逆映射的操作
c) Channel:包含socket、file和pipe三种管道,它实际上是双向交流的通道
d) Selector:它将多元异步I/O操作集中到一个或多个线程中(它可被看成UNIX中select()或Win32中WaitForSingleEvent()的面向对象版本)
NIO API引入一种称为通道的新型原始I/O提取方法。通道表示到实体(如硬件设备、文件、网络套接字或可执行一个或多个诸如读写I/O操作的程序组件)的开放连接。通道可以处于打开或关闭状态,既是可异步关闭的,又是可中断的。
有几个接口对Channel接口进行了扩展,每个接口指定一个新的I/O操作。以下是其中几个接口的信息:
ReadableByteChannel指定一个将字节从通道读入缓冲器的read()
WritableByteChannel指定一个将字节从通道写入缓冲器的write()
ScatteringByteChannel和GatheringByteChannel分别扩展ReadableByteChannel和WritableByteChannel,采用缓冲器序列而非一个单独缓冲器增加read()和write()
FileChannel支持从连接到文件的通道读取字节或向其写入字节,及查询和修改当前的文件位置和将文件调整为指定大小等常见操作
使用FileChannel读写文件,例:
public void copyFile(String fileFrom, String fileTo) throws IOException { FileInputStream inStream = new FileInputStream(fileFrom); FileOutputStream outStream = new FileOutputStream(fileTo); FileChannel inChannel = inStream.getChannel(); FileChannel outChannel = outStream.getChannel(); ByteBuffer byteBuf = ByteBuffer.allocate(512); while (true) { byteBuf.clear(); int n = inChannel.read(byteBuf); if (n == 0 || n ==1) { break; } byteBuf.flip(); outChannel.write(byteBuf); } byteBuf = null; inChannel.close(); inChannel = null; outChannel.close(); outChannel = null; inStream.close(); inStream = null; outStream.close(); outStream = null; }
使用FileChannel读取文本文件内容,例:
public void readFile(String file, String charset) throws IOException { FileInputStream inStream = new FileInputStream(file); FileChannel inChannel = inStream.getChannel(); ByteBuffer byteBuf = ByteBuffer.allocate(512); String content; while (true) { byteBuf.clear(); int n = inChannel.read(byteBuf); if (n == 0 || n == -1) { break; } byteBuf.flip(); content = new String(byteBuf.array(), charset); System.out.print(content); } byteBuf = null; content = null; inChannel.close(); inChannel = null; inStream.close(); inStream = null; }
非阻塞操作是NIO最常见与最广泛应用的功能。需要调用SelectableChannel中的configureBlocking()方法配置阻塞或非阻塞操作(在阻塞方式下调用读、写或其他操作,直到操作完成才能返回)。
非阻塞I/O最为显著的性能优势包括:
· 可以进行非阻塞异步输入/输出
· 能锁定整个或部分文件
在非阻塞方式下,SelectableChannel对象通过register()向Selector对象注册,然后签署特殊事件。在指定操作发生时,Selector对象就会发出通知。这些事件由SelectionKey的域反映。
例:
… InetSocketAddress addr = new InetSocketAddress(hostname, port); SocketChannel channel = SocketChannel.open(); channel.configureBlocking(false); channel.connect(addr); …
在connect()后,它将立即返回执行情况。然后,你必须指出如何处理这样的通道连接,这时有:
… Selector selector = Selector.open(); channel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ); …
在收到通知后,又有:
… while (selector.select(500) > 0) { Set<SelectionKey> readyKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = readyKeys.iterator(); SelectionKey key; while (iterator.hasNext()) { key = iterator.next(); iterator.remove(); SocketChannel chan = (SocketChannel) key.channel(); if (key.isConnectable()) { … } else if (key.isReadable()) { … } } } …
相关推荐
通过阅读和学习这些JAVA学习笔记,开发者不仅可以掌握JAVA编程的基本技能,还能深入了解其设计理念,从而更好地应对各种实际开发问题。不断更新和完善自己的JAVA知识体系,对于成为一名优秀的JAVA开发者至关重要。
"Java学习笔记——良葛格"是一份专为初学者设计的教程资料,由良葛格精心编写,旨在帮助读者掌握JDK5.0版本的Java基础知识。JDK(Java Development Kit)是Java开发的核心工具集,包含了编译器、调试器和运行环境等...
这份“Java JDK 6学习笔记——ppt简体版”涵盖了Java语言的核心概念、语法特性以及JDK 6的新功能,旨在帮助初学者和有经验的开发者深入理解并掌握这一版本的Java开发环境。 首先,Java JDK 6的安装与配置是学习的...
Java JDK 6学习笔记是为Java初学者量身定制的一份宝贵资料,它涵盖了Java编程的基础概念、语法以及核心特性。这份PPT简体版旨在帮助读者快速掌握Java开发的基本技能,逐步成为一名合格的Java程序员。 Java JDK...
此外,`java.txt`可能包含了关于Java语言基础和进阶概念的文本资料,涵盖变量、数据类型、控制结构、类与对象、继承、多态等核心概念。这些内容对于理解和掌握Java编程至关重要。 通过"Java JDK 6学习笔记——ppt...
在Java编程语言中,NIO(New Input/Output)是一个重要的特性,它为开发者提供了非阻塞I/O操作的能力,极大地提高了程序的性能。本文主要关注的是Java NIO中的ByteBuffer,一个关键的数据容器,用于在通道(Channel)...
Java JDK 6学习笔记——PPT简体版是针对初学者和有经验的开发者们的一份宝贵资源,它深入浅出地介绍了Java编程语言的核心概念和技术。这份资料以PPT的形式呈现,使得学习过程更加直观易懂,同时包含了课程中的源代码...
这份"个人学习的java笔记——思维导图"涵盖了上述诸多Java编程的核心知识点,通过思维导图的方式,使得学习者可以更直观地理解和记忆这些复杂的概念,对提升Java学习效果大有裨益。无论你是初学者还是有经验的开发者...
这份"Java笔记——2017年3月3日"涵盖了多个关键概念,对于深入理解Java编程至关重要。下面将逐一详解这些知识点: 1. **泛型**:泛型是Java 5引入的一项特性,它允许在类、接口和方法中使用类型参数,增强了代码的...
Java JDK 5.0是Java开发工具包的一个重要版本,它在2004年发布,引入了许多新特性,极大地增强了Java编程语言的功能和效率。良葛格的《Java JDK5.0学习笔记》是一本面向初学者的教程,旨在帮助读者掌握这个版本的...
本学习笔记主要涵盖了Java的基础知识,包括面向对象、集合、IO流、多线程、反射与动态代理以及Java 8的新特性等方面,旨在帮助初学者或有经验的开发者巩固和提升Java编程技能。 1. 面向对象(OOP):Java的核心是...
**J2SE学习笔记——接口与相关程序** Java 2 Platform, Standard Edition(J2SE)是Java平台的核心部分,提供了开发和运行桌面应用程序、Web应用程序和服务的基础。本笔记主要聚焦于J2SE中的接口(Interface)概念...
- **类与对象**:Java是面向对象的语言,学习如何定义类,创建和使用对象。 - **封装、继承、多态**:封装是隐藏实现细节,提供公共接口;继承使得子类可以继承父类的属性和方法;多态则是接口的多种实现方式。 -...
Java是一种广泛使用的面向对象的编程语言,其核心编程概念包括...了解并掌握这些Java核心编程概念是编写有效、可维护Java代码的基础。在实际编程中,还需要结合良好的编程实践和设计模式,以提高代码质量和可读性。