复习集合

1. 迭代器

迭代器:接口

接口:定义标准

为什么迭代器使用接口?

通过迭代器接口,可以定义多个不同类型的迭代器,每个迭代器可以根据不同的数据结构进行实现(要迭代的数据结构不同),这样就可以在不同情况下使用不同类型的迭代器,而无需修改迭代器的代码。

default void remove() { throw new UnsupportedOperationException("remove");}

迭代器底层实现中的remove()方法被设置为抛出UnsupportedOperationException异常的原因是为了保持迭代器的一致性和安全性。

迭代器的主要目的是提供一种遍历集合元素的方式,并且允许在遍历过程中删除元素。然而,并非所有的集合都支持在遍历过程中进行元素的删除操作,因为删除操作可能会导致迭代器的状态不一致。

为了解决这个问题,Java的迭代器接口中提供了remove()方法,该方法用于从底层集合中删除迭代器最后访问的元素。但是,并不是所有的集合都实现了remove()方法。如果集合不支持删除操作,调用remove()方法可能会导致不一致的状态。为了避免这种情况,迭代器接口的默认实现中将remove()方法设置为抛出UnsupportedOperationException异常。

这样做的好处是,当使用不支持删除操作的迭代器时,如果尝试调用remove()方法,会立即抛出异常,提醒开发者该集合不支持删除操作,避免产生不一致的状态。

需要注意的是,如果需要在迭代过程中删除元素,应该确保使用的是支持删除操作的迭代器,如ArrayList的迭代器,而不是不支持删除操作的迭代器,如Collections.unmodifiableList()返回的迭代器。

默认方法:实现类去重写

2.迭代器底层

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    //外部操作数:记录添加数据、删除数据的次数(记录元素个数变化的次数)
 	protected transient int modCount = 0;//4
}
public class ArrayList<E> extends AbstractList<E> implements List<E>{
    //数据容器
    transient Object[] elementData;//["aaa","bbb","ccc","ddd",null,null,...]
    //元素个数/指针
    private int size;//4
    
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }
    
    public Iterator<E> iterator() {
        return new Itr();
    }
    
    private class Itr implements Iterator<E> {
        int cursor;       // 游标 - 4
        int lastRet = -1; // 遍历当前元素的下标 - 3
        int expectedModCount = modCount;//内部操作数 - 4

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();//判断内外操作数是否一致,不一致就报错
            //i = 3
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            //获取外部对象中的容器
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                //迭代器内部还是使用ArrayList的remove方法去做删除
                ArrayList.this.remove(lastRet);
                //把当前的元素下标赋值给游标
                cursor = lastRet;
                lastRet = -1;
                //重新将外部操作数赋值给内部操作数,保证了内外部操作数是一致的
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        final void checkForComodification() {
            //外部操作数不等于内部操作数就报错
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
}
找场景:
    ArrayList<String> list = new ArrayList<>();
    list.add("aaa");
    list.add("bbb");
    list.add("ccc");
    list.add("ddd");

    Iterator<String> it = list.iterator();
    while(it.hasNext()){
        String element = it.next();
        System.out.println(element);
    }

线程

1. 线程的创建

进程 与 进程 的关系:独享内存空间和系统资源

线程 与 进程 的关系:有一个进程中至少包含一个线程

线程 与 线程 的关系:在同一个进程里,多个线程共享内存空间和系统资源

一个进程中包含多个线程,只有一个主线程

经典面试题:请问当我们编写一个单纯的main方法时,此时该程序是否为单线程的?为什么?

垃圾回收器是一个后台线程

1.线程类

创建MyThread类,继承Thread,重写run方法

//创建MyThread类
package com.wz.thread01;

//线程类
public class MyThread extends Thread{

	//线程是进程中的一条执行路径(功能),线程里的功能就写在run方法中
	//当前线程对象抢到CPU资源后才会调用run方法
	@Override
	public void run() {
		System.out.println("MyThread的run方法被调用了");
	}
}
package com.wz.thread01;

public class Test01 {
	/**
	 * 知识点:创建线程 -- 线程类
	 * 步骤:
	 * 		1.创建线程类(MyThread),继承Thread
	 * 		2.重写run方法
	 * 		3.在测试类中创建线程类的对象 -- MyThread t = new MyThread();
	 * 		4.启动子线程 -- t.start();
	 */
	public static void main(String[] args) {
		
		//子线程的对象
		MyThread t = new MyThread();
		//启动子线程
		t.start();	
	}
}

2.任务类

创建Task类,实现Runnable接口中的run方法

package com.wz.thread02;

public class Task implements Runnable{
    //当前线程抢到CPU资源后,才会调用任务类对象中的run方法
    @Override
    public void run() {
        System.out.println("Task的run方法被调用");
    }
}
package com.wz.thread02;

public class test01 {
    /**
     * 知识点:创建线程 -- 任务类
     *
     * 步骤:
     * 	1.创建任务类(Task),实现Runnable
     * 	2.重写run方法
     * 	3.创建任务类对象 - Task task = new Task();
     * 	4.创建子线程对象,并将任务类对象传入到子线程中 - Thread t = new Thread(task);
     * 	5.启动子线程
     */
    public static void main(String[] args) {
        //任务对象
        Task task = new Task();
        //创建子线程对象
        Thread t = new Thread(task);
        t.start();
    }
}

3.带返回值的任务类

4.线程池

2. 感受线程之间资源争抢

需求:编写一个多线程的应用程序,主线程打印1-100之间的数字,子线程打印200-300之间的数字,观察其输出的结果,体会多线程互相争抢资源的场景

package com.wz.thread03;

public class test01 {
    /**
     * 需求:编写一个多线程的应用程序
     * 主线程打印1-100之间的数字,子线程打印200-300之间的数字
     * 观察其输出的结果,体会多线程互相争抢资源的场景
     * @param args
     */
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        //主线程
        for (int i = 1; i <= 100; i++) {
            System.out.println("主线程--"+i);
        }
    }
}
package com.wz.thread03;

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 200; i <= 300 ; i++) {
            System.out.println("子线程--"+i);
        }
    }
}

3. 线程的优先级别,setPriority

需求:在主线程中创3个子线程,并且设置不同优先级,观察其优先级对线程执行结果的”影响”。

package com.wz.thread04;

public class A extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("A线程---"+i);
        }
    }
}

package com.wz.thread04;

public class B extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("B线程---"+i);
        }
    }
}


package com.wz.thread04;

public class C extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("C线程---"+i);
        }
    }
}
package com.wz.thread04;

public class test01 {
    /**
     * 知识点:线程的优先级别
     *
     * 需求:在主线程中创3个子线程,并且设置不同优先级,观察其优先级对线程执行结果的”影响”。
     */
    public static void main(String[] args) {
        //创建线程对象
        A a = new A();
        B b = new B();
        C c = new C();
        //设置线程的优先级别
        a.setPriority(Thread.MAX_PRIORITY);
        b.setPriority(Thread.NORM_PRIORITY);
        c.setPriority(Thread.MIN_PRIORITY);
        //启动子线程
        a.start();
        b.start();
        c.start();
    }
}

线程的优先级别:1~10,数字越大,优先级别越高* 理解:优先级别越高,抢到资源的概率越大,但是结果不是绝对的,只是影响而已

4. 代码优化(给线程取名字)

  1. 自己写getThreadName/setThreadName
  2. 调用父类的一个参数的构造方法和getName
  3. Thread.currentThread().getName()
package com.wz.thread05;

public class MyThread extends Thread{
    private String threadName;

    public MyThread(String threadName) {
        this.threadName = threadName;
    }
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println(threadName+"----"+i);
        }
    }
}
package com.wz.thread05;

public class test01 {
    public static void main(String[] args) {
        MyThread a = new MyThread("A");
        MyThread b = new MyThread("B");
        MyThread c = new MyThread("C");
        //设置线程优先级别
        a.setPriority(Thread.MAX_PRIORITY);
        b.setPriority(Thread.NORM_PRIORITY);
        c.setPriority(Thread.MIN_PRIORITY);
        //启动线程
        a.start();
        b.start();
        c.start();
    }
}

package com.qf.thread06;

public class MyThread extends Thread{
	
	public MyThread(String name) {
		super(name);
	}

	@Override
	public void run() {
		for (int i = 1; i <= 100; i++) {
			
			//获取当前线程对象
			Thread currentThread = Thread.currentThread();
			//获取当前线程对象的名字
			String n = currentThread.getName();
			System.out.println(n + ":" + i);
		}
	}
}