一、集合
1、什么是集合
概念: 对象的容器,存储对象的对象,可代替数组
和数组区别:(1)、数组长度固定,集合长度不固定。(2)、数组可以存在基本类型和引用类型,集合只能存在引用类型。
特点: 容器的工具类,定义了对多个对象进行操作的常用方法
位置: java.util.*;
2、Collection父接口
特点: 代表一组任意类型的对象,无序、无下标
Collection常用方法
Arraylist.add(Object obj) //添加一个对象
Arraylist.addAll(Collection c) //将一个集合中的所有对象添加到此集合
clear() //清空此集合中的所有对象
Arraylist.contains(Object o) //检查此集合中是否包含o对象
Arraylist.equals(Object o) //比较此集合是否与指定对象相等
Arraylist.idEmpty() //判断此集合是否为空
Arraylist.remove(Object o) //在此集合中移除o对象
.size() //返回此集合中的元素个数
Arraylist.toArray() //将此集合转换成数组
//方法使用
public class textArrayList{
public static void main(String[] args){
//创建ArrayList
Collection arr = new ArrayList();
//add添加元素
arr.add("ABC");
arr.add("DEG");
arr.add("HIM");
System.out.println(arr);//结果:[ABC, DEG, HIM]
System.out.println("元素个数:"+arr.size());//结果:元素个数:3
arrayList.remove("ABC");
System.out.println(arr);//结果:[DEG, HIM]
}
}
3、List子接口
特点: 有序、有下标、元素可以重复
List实现类
ArrayList(重点)
数组结构实现,查询快、增删慢
JDK1.2版本,运行效率快、线程不安全
Vector
数组结构实现,查询快、增删慢
JDK1.0版本,运行效率慢、线程安全
LinkedList
链表结构实现,增删快,查询慢
List常用方法
Arraylist.add(int index, Object o) //在index位置插入对象o
Arraylist.addAll(int index, Collection c) //将一个集合中的元素添加到集合中的index位置
Arraylist.get(int index) //返回集合中指定位置的元素
Arraylist.subList(int fromIndex, int toIndex) //返回fromIndex和toIndex之间的集合元素
public class textArrayList{
public static void main(String[] args){
List list = new ArrayList();
list.add("abc");
list.add("ghi");
list.add(1,"def");
System.out.println(list);//结果:[abc, def, ghi]
list.addAll(0,arrayList);
System.out.println(list);//结果:[DEG, HIM, abc, def, ghi]
}
}
4、Set子接口
特点: 无序、无下标、元素不可重复
方法: 全部继承自Collection中的方法
Set实现类
HashSet
基于HashCode实现元素不重复
当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入
LinkedHashSet
链表实现的HashSet,按照链表进行存储,即可保留元素的插入顺序
TreeSet
基于排列顺序实现元素不重复
实现了SortedSet接口,对集合元素自动排序
元素对象的类型必须实现Comparable接口,指定排序规则
通过CompareTo方法确定是否为重复元素
5、Map接口
特点: 存储一对数据(Key-Value),无序、无下标,键不可重复,值可重复
map接口常用方法
map.put(K key, V value) //将对象存入到集合中,关联键值。key重复则覆盖原值
map.get(Object key) //根据键获取对应的值
keySet //返回所有key
Collection values() //返回包含所有值的Collection集合
Set<Map.Entry<K, V>> //键值匹配的Set集合
public class textArrayList{
public static void main(String[] args){
Map map = new HashMap();
map.put("one","你好");
map.put("twe","世界");
System.out.println(map);//结果:{twe=世界, one=你好}
System.out.println(map.get("one"));//结果:你好
System.out.println(map.keySet());//结果:[twe, one]
System.out.println(map.values());//结果:[世界, 你好]
}
}
Map实现类
HashMap
JDK1.2版本,线程不安全,运行效率快;允许用null 作为key或是value
Hashtable
JDK1.0版本,线程安全,运行效率慢;不允许用null作为key或是value
Properties
Hashtable的子类,要求key和value都是String。通常用于配置文件的读取
TreeMap
实现了SortedMap接口(是Map子接口),可以对key自动排序
6、增强for
可遍历集合或数组
for(数据类型 变量名 : 容器名称){ //可遍历集合或数组(常用在无序集合上)
//System.out.println();
}
for (Object string : map.values()){
System.out.println(string);
}
/*结果: 世界
你好
*/
小总结
- 集合的概念
对象的容器,存储对象的对象,定义了对多个对象进行操作的常用方法 - List集合
有序、有下标、元素可以重复。(ArrayList、LinkedList、Vector) - Set集合
无序、无下标、元素不可重复。(HashSet、LinkedHashSet、TreeSet) - Map集合
存储一对数据,无序、无下标,键不可重复,值可重复。(HashMap、HashTable) - Collections
集合工具类,定义了除了存取以外的集合常用方法
二、多线程
1、简单了解
什么是进程
程序是静止的,只有真正运行的程序才被称为进程
什么是线程
线程,又称轻量级进程
程序中的一个顺序控制流程,同时也是CPU的基本调度单位
- 就如,网盘是一个进程,当中的多个下载任务就是多个线程。
- jvm是一个进程,当中默认包含主线程(Main函数),可通过代码创建多个独立线程,与Main并发执行
2、线程组成
- CPU时间片: 操作系统(OS)会为每个线程分配时间
- 堆空间: 存储线程需使用的对象,多个线程可以共享堆中的对象
栈空间: 存储线程需使用的局部变量,每个线程都拥有独立的栈 - 线程的逻辑代码
创建线程
//第一种方式
public class textThread{
public static void main(String[] args){
//new进行创建
Son son = new Son();
son.start();//start()方法启动
}
}
//extends thread类
class Son extends Thread{
//重写run
@Override
public void run(){
···实现代码
}
}
//第二种方式
public class textThread{
public static void main(String[] args){
//new进行创建
Son son = new Son();
//new Thread进行
Thread thread = new Thread(son);
thread.start();//start()方法启动
}
}
//实现Runnable接口
class Son implements Runnable{
//重写run
@Override
public void run() {
···实现代码
}
}
3、线程的状态
基本状态
线程休眠
.sleep(long millis);
//millis毫秒:1000millis=1s
睡眠的位置:为了让其他线程有机会执行,可以将Thread.sleep()的调用 放线程run()之内。这样才能保证该线程执行过程中会睡眠。
public class textSleep {
public static void main(String[] args) {
Son son = new Son();
son.start();
}
}
class Son extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("sleep"+i);
//在for里面,让线程输出一次就睡眠1s
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//让线程输出完for就睡眠2s
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//睡眠2s后运行
for (int i = 0; i < 5; i++) {
System.out.println("peels"+i);
}
}
}
注意点:
1、线程睡眠是帮助所有线程获得运行机会的最好方法。
2、线程睡眠到期自动苏醒,并返回到可运行状态,不是运行状态。 sleep()中指定的时间是线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就开始执行。
3、sleep()是静态方法,只能控制当前正在运行的线程。
线程放弃
.yield()
//当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片
public class text10 {
public static void main(String[] args) {
Son2 son2 = new Son2();
son2.start();
Son1 son = new Son1();
son.start();
}
}
class Son2 extends Thread{
@Override
public void run() {
yield();//主动放弃时间片
for (int i = 0; i < 5; i++) {
System.out.println("yield"+i);
}
}
}
class Son1 extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("sleep"+i);
try {
sleep(1000);//睡眠1s看看
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
结果:
线程结合
.join()
//允许其他线程加入到当前线程中,等待加入的线程执行完毕后,此线程再去竞争时间片执行
public class textJoin{
public static void main(String[] args){
//new创建son3就行
Son3 son = new Son3();
son.start();
}
}
class Son3 extends Thread{
// 创建son4
Son4 son4 = new Son4();
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("我"+i);
}
try {
son4.start();//start方法准备
son4.join();//结合son4
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Son4 extends Thread{
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
}
}
4、线程安全
线程安全问题
这样可能会造成数据错误问题
解决线程安全问题的方法
进行同步代码块、同步方法
//对临界资源对象加锁
synchronized(临界资源对象) {
代码(原子操作)
}
//对当前对象(this)加锁
synchronized 返回值类型 方法名称(形参列表0) {
代码(原子操作)
}
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
修饰一个代码块
public class textThread {
public static void main(String[] args) {
textSynchThread sy = new textSynchThread();
Thread thread = new Thread(sy);
Thread thread1 = new Thread(sy);
thread.start();
thread1.start();
}
}
class textSynchThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("线程" + i);
}
/*
synchronized(this) {
for (int i = 0; i < 10; i++) {
System.out.println("线程" + i);
}
}
*/
}
}
结果:
public class text11 {
public static void main(String[] args) {
textSynchThread sy = new textSynchThread();
Thread thread = new Thread(sy);
Thread thread1 = new Thread(sy);
thread.start();
thread1.start();
}
}
class textSynchThread implements Runnable{
@Override
public void run() {
synchronized(this) {
for (int i = 0; i < 10; i++) {
System.out.println("线程" + i);
}
}
}
}
结果:
当两个并发线程(thread和thread1)访问同一个对象(syncThread)中的synchronized代码块时,在同一时刻只能有一个线程得到执行,另一个线程受阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。
当然,当一个线程访问对象的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块。
同步代码块范围是{}里
修饰一个方法
public class text11 {
public static void main(String[] args) {
textSynchThread sy = new textSynchThread();
Thread thread = new Thread(sy);
Thread thread1 = new Thread(sy);
thread.start();
thread1.start();
}
}
class textSynchThread implements Runnable{
@Override
public synchronized void run() {
for (int i = 0; i < 10; i++) {
System.out.println("线程" + i);
}
}
}
修饰方法范围是整个函数
5、线程通信
概述: 线程与线程之间不是相互独立的个体,它们彼此之间需要相互通信和协作
wait/notify 机制
wait()——让当前线程 (Thread.concurrentThread() 方法所返回的线程) 释放对象锁并进入等待(阻塞)状态。
notify()——唤醒一个正在等待相应对象锁的线程,使其进入就绪队列,以便在当前线程释放锁后竞争锁,进而得到CPU的执行。
notifyAll()——唤醒所有正在等待相应对象锁的线程,使它们进入就绪队列,以便在当前线程释放锁后竞争锁,进而得到CPU的执行。
public class text11 {
public static void main(String[] args) {
Wait wait = new Wait();
Notify notify = new Notify();
wait.start();
notify.start();
}
}
class Wait extends Thread{
@Override
public void run() {
synchronized (this){
System.out.println("线程"+Thread.currentThread().getName());
try {
System.out.println("wait并释放"+Thread.currentThread().getName());
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("完成");
}
}
}
class Notify extends Thread{
@Override
public void run() {
synchronized (this){
System.out.println("线程"+Thread.currentThread().getName());
notify();
System.out.println("线程唤醒"+Thread.currentThread().getName());
}
System.out.println("完成");
}
}
6、线程池
线程池:线程容器,可设定线程分配的数量上限,将预先创建的线程对象存入池中,并重用线程池中的线程对象,避免频繁的创建和销毁。
(回顾时补充···)