最近想学一下java基础(三)

集合

集合按照其存储结构可以分为两大类,分别是单列集合java.util.Collection和双列集合java.util.Map,今天我们主要学习Collection单列集合,在day04时讲解Map双列集合。

  • Collection:单列集合类的根接口,用于存储一系列符合某种**规则(抽象方法)**的元素,

    它有两个重要的子接口,分别是java.util.Listjava.util.Set

    List的特点是元素有序、元素可重复,有索引相反的是,Set的特点是元素无序,而且不可重复,无索引。

    List接口的主要实现类有java.util.ArrayListjava.util.LinkedListSet接口的主要实现类有java.util.HashSetjava.util.TreeSet

从上面的描述可以看出JDK中提供了丰富的集合类库,为了便于初学者进行系统地学习,接下来通过一张图来描述整个集合类的继承体系。

在这里插入图片描述

其中,橙色框里填写的都是接口类型,而蓝色框里填写的都是具体的实现类。这几天将针对图中所列举的集合类进行逐一地讲解。

集合本身是一个工具,它存放在java.util包中。在Collection接口定义着单列集合框架中最最共性的内容

Collection 接口常用功能(说出Collection集合的常用功能,从增删改查的角度去出发想象即可)

Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合。方法如下:

  • public boolean add(E e): 把给定的对象添加到当前集合中 。//增
  • public boolean remove(E e): 把给定的对象在当前集合中删除。//删一个
  • public void clear() :清空集合中所有的元素。//删除所有
  • public Object[] toArray(): 把集合中的元素,存储到数组中。//改,变成数组,转换成数组
  • public boolean contains(E e): 判断当前集合中是否包含给定的对象。//查,是否包含元素,针对的是一个
  • public boolean isEmpty(): 判断当前集合是否为空。//查,是否没有元素,针对的是所有情况
  • public int size(): 返回集合中元素的个数。//查,元素的个数,针对的也是所有情况

Iterator迭代器

迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就再取出来。直到把集合中的所有元素全部取出。这种取出方式,专业术语称为迭代。
Iterator接口的常用方法如下:

  • public E next():返回迭代的下一个元素(迭代器原理内置了一个指针,一开始在集合的外面,每调用一次next方法,指针向下移动一次,得到对应的元素)。
  • public boolean hasNext():如果仍有元素可以迭代,则返回 true。
public class IteratorDemo {
  	public static void main(String[] args) {
        // 使用多态方式 创建对象
        Collection<String> coll = new ArrayList<String>();

        // 添加元素到集合
        coll.add("串串星人");
        coll.add("吐槽星人");
        coll.add("汪星人");
        
        //能够使用迭代器对集合进行取元素
        //使用迭代器 遍历   每个集合对象都有自己的迭代器
        Iterator<String> it = coll.iterator();//调用方法.var生成迭代器
        //  泛型指的是 迭代出 元素的数据类型
        while(it.hasNext()){ //判断是否有迭代元素
            String s = it.next();//获取迭代出的元素
            System.out.println(s);
        }
  	}
}

异常

异常指的是程序在执行( 编译和运行)过程中,出现的非正常的情况,最终会导致JVM的非正常停止(中断)

在这里插入图片描述
Throwable体系:

  • Error:严重错误Error,无法通过处理的错误,只能事先避免,好比绝症。
  • Exception:表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的。好比感冒、阑尾炎。

异常的处理

声明异常throws,throw产生一个真实具体的问题,throws问题的处理方式,不负责任处理,交给jvm,中断,问题类型,原因,位置

捕获异常try…catch,不是throws踢皮球不负责的处理,而是自己能处理,自己处理,既然是自己处理,没有交个jvm,所以没有中断,后续代码继续执行!!!(throws踢皮球方式最终交个jvm中断,后续代码不再执行!!!)

try-catch的方式就是捕获异常。

  • 捕获异常:Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理。

捕获异常语法如下:

try{//尝试,试验,检测,需要时间,越少越好
     编写可能会出现异常的代码
}catch(异常类型  e){//e=对象;//如果上面出现问题,立马catch块抓住它,进行捕获
     处理异常的代码
     //记录日志/打印异常信息/继续抛出异常//待会说
}

**try:**该代码块中编写可能产生异常的代码。

**catch:**用来进行某种异常的捕获,实现对捕获到的异常进行处理。
**

在idea中添加try/catch的快捷键 ctrl+alt+t 选中想被try/catch包围的语句,同时按下ctrl+alt+t,

**

finally代码块,跟try或者trycatch组合用的,不能单独使用,最终的,里面的代码永远都会执行,除非你在它之前退出Java虚拟机,用这行代码,System.exit(0);,程序立马停止,后面的代码不走

注意:finally不能单独使用。

多线程

进程:进行中的程序
线程:进程中的执行路径(执行路径,能做事情的地方,通道,路径)

并行:指两个或多个事件在同一时刻发生(同时发生)。(说白了,并行就是多个事情同时进行,需要多核(多个)CPU,一个CPU在执行一个事情同时,另外一个cpu在同时执行另外的事情!!!)
并发:指两个或多个事件在同一个时间段内发生。(说白了,并发,发,发作是需要时间的,不是同时进行,cpu一行执行那个事情,一会执行另外的事情,由于CPU切换的非常快,你看起来以为是同时进行,但其实并不是!!!)

进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个线程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
线程:进程内部的一个独立执行单元(路径);一个进程可以同时并发的运行多个线程,可以理解为一个进程便相当于一个单 CPU 操作系统,而线程便是这个系统中运行的多个任务。

线程同步,同步技术,解决线程的安全性问题

同步就可以让cpu在某段时间内只让一个线程进来做事情,其他线程不能进来,等你做完了才能一个一个进来(理解为排队一个个来不会有问题),同步技术包括,同步代码块,同步方法,Lock锁//记忆

当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题。

要解决上述多线程并发访问一个资源的安全性问题:也就是解决重复票与不存在票问题,Java中提供了同步机制(synchronized)来解决。

根据案例简述:

窗口1线程进入操作的时候,窗口2和窗口3线程只能在外等着,窗口1操作结束,窗口1和窗口2和窗口3才有机会进入代码去执行。也就是说在某个线程修改共享资源的时候,其他线程不能修改该资源,等待修改完毕同步之后,才能去抢夺CPU资源,完成对应的操作,保证了数据的同步性,解决了线程不安全的现象。

为了保证每个线程都能正常执行原子操作,Java引入了线程同步机制。

那么怎么去使用呢?有三种方式完成同步操作:

  1. 同步代码块。
  2. 同步方法。
  3. 锁机制。

同步代码块

  • 同步代码块synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

格式:

synchronized(同步锁){//锁对象可以是任意的,但是如果这个同步代码块被多次调用,要求锁对象是唯一,才能里面代码锁起来,同步的效果,只让一个线程进来搞事情,相当于你锁上门搞事情,别人不能进来
     需要同步操作的代码,同步一个个线程,只让一个线程进来搞事情,其他线程不能进来,在外面等着,等你做完事情,释放锁才能一个个进来
}//做完事情,释放锁,要求是同一把锁

同步锁:

对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.

  1. 锁对象 可以是任意类型。

  2. 多个线程对象 要使用同一把锁。

注意:在任何时候,最多**允许一个线程拥有同步锁,**谁拿到锁就进入代码块,其他的线程只能在外等着(BLOCKED进入阻塞状态)。

使用同步代码块解决代码:

public class Ticket implements Runnable{
	private int ticket = 100;
	
	static Object lock = new Object();//共享的,大家都用同一个,同一把锁
	/*
	 * 执行卖票操作
	 */
	@Override
	public void run() {
		//每个窗口卖票的操作 
		//窗口 永远开启 
		while(true){
			synchronized (lock) {//字节码对象,this,"锁"锁对象唯一,同一把锁,里面锁起来,只让一个线程进来搞事情
				if(ticket>0){//有票 可以卖
					//出票操作
					//使用sleep模拟一下出票时间 
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					//获取当前线程对象的名字 
					String name = Thread.currentThread().getName();
					System.out.println(name+"正在卖:"+ticket--);
				}
			}
		}
	}
}

当使用了同步代码块后,上述的线程的安全问题,解决了。

同步方法,同步的效果,只让一个线程进来搞事情,相当于你锁上门搞事情,别人不能进来

  • 同步方法:使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。

格式:

public  synchronized void method(){
   	可能会产生线程安全问题的代码
}

同步锁是谁?

​ 对于非static方法,同步锁就是this。

​ 对于static方法,我们使用当前方法所在类的字节码对象(类名.class)。

使用同步方法代码如下:

public class Ticket implements Runnable{
	private int ticket = 100;
	/*
	 * 执行卖票操作
	 */
	@Override
	public void run() {
		//每个窗口卖票的操作 
		//窗口 永远开启 
		while(true){
			sellTicket();
		}
	}
	
	/*
	 * 锁对象 是 谁调用这个方法 就是谁 
	 *   隐含 锁对象 就是  this
	 *    
	 */
	public synchronized void sellTicket(){//this锁对象
        if(ticket>0){//有票 可以卖	
            //出票操作
            //使用sleep模拟一下出票时间 
            try {
              	Thread.sleep(100);
            } catch (InterruptedException e) {
              	// TODO Auto-generated catch block
              	e.printStackTrace();
            }
            //获取当前线程对象的名字 
            String name = Thread.currentThread().getName();
            System.out.println(name+"正在卖:"+ticket--);
        }
	}
}
//非静态同步方法,锁对象是什么呢?是this
//静态同步方法,锁对象是这个方法所在的类的字节码对象,类名.class

Lock锁,接口

jdk1.5开始支持下面内容

java.util.concurrent.locks.Lock机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。

Lock锁也称同步锁,加锁与释放锁方法化了,如下:

  • public void lock():加同步锁。
  • public void unlock():释放同步锁。

使用如下:

public class Ticket implements Runnable{
	private int ticket = 100;
	
	Lock lock = new ReentrantLock();//多态写法,父接口引用指向接口的实现类对象
	/*
	 * 执行卖票操作
	 */
	@Override
	public void run() {
		//每个窗口卖票的操作 
		//窗口 永远开启 
		while(true){//Runnable共享资源,同一个锁对象
			lock.lock();//上锁,相当于关门,互斥锁,一个线程进来
			if(ticket>0){//有票 可以卖
				//出票操作 
				//使用sleep模拟一下出票时间 
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				//获取当前线程对象的名字 
				String name = Thread.currentThread().getName();
				System.out.println(name+"正在卖:"+ticket--);
			}
			lock.unlock();//释放锁,相当于开门
		}
	}
}
发布了30 篇原创文章 · 获赞 0 · 访问量 2447

猜你喜欢

转载自blog.csdn.net/duanduan339/article/details/105550412