Java 基础知识笔记更新中

1.Java 集合说明
顶级接口
Collection
Collection 顶级接口下面有list和set两个父级接口
list和set的区别
1.1 有序性
list 是有序的,保证按插入顺序排序
set 是无序的,存入和取出的顺序不一致
唯一性
list不唯一可以出现重复元素
set元素唯一不允许重复
获取元素方式
list 可以通过索引直接操作元素
set 不能根据索引获取元素
1.2 list相关实现类比较

ArrayList:底层是数组,查询快,增删慢,线程不安全,效率高,可以存储重复元素
LinkedList: 底层数据结构是链表,查询慢,增删快,线程不安全,效率高,可以存储重复元素
Vector: 底层是数组,查询快,增删慢,线程安全,效率低,可以存储重复元素

1.3 set相关实现类比较

hashSet 底层数据结构采用哈希表实现,元素无序且唯一,线程不安全,效率高,可以存储null 元素,
元素的唯一性是靠存储元素类型是否重写hashCode() 和 equals() 方法保证的

LinkedHashSet 底层数据结构采用链表和哈希表共同创建,链表保证元素的顺序与存储顺序一致,
哈希表保证元素的唯一性。线程不安全,效率高。
 
TreeSet底层数据结构是二叉树实现, 元素唯一且已经排好序 不允许放入 null

1.4 map详解

map用于保存具有映射关系的数据,map里面保存着两组数据:key和value,它们都可以使用任何引用类型的数据
,但key不可以重复。所以通过指定的key就可以取出对应的value。

**hashMap 和 hashtable 比较**

线程安全方面:
       hashtable 是同步的,这个类中的一些方法加入了synchronized 关键字,保证了hashtable中的对象是
    线程安全的
	    hashMap 是异步的,因此hashMap中的对象并不是线程安全的
空值方面:
        hashMap 可以让你将空值作为一个表的条目的key或value,但是hashtable是不能放入空值的
		hashMap 最多只有一个key值为null,但可以有无数个value值为null
性能方面:
         hashMap的性能好,hashtable性能差

用作key的对象必须实现hashCode和equals方法
 
不能保证其中的键值对的顺序

尽量不要使用可变对象作为它们的key值 

TreeMap 是一个有序的key-value集合,它通过红黑树实现
TreeMap 是一个key-value集合
TreeMap 实现了NavigableMap接口,意味着它支持一系列的导航方法,比如返回有序的key集合
TreeMap 实现java.io.Serializable接口,意味着它支持序列化
TreeMap基于红黑树实现,该映射根据其键的自然顺序进行排序
或根据创建映射时提供的Comparator 进行排序,取决与使用的构造方法

TreeMap 时非同步的 线程不安全,效率低。

1.5 与synchronized 自动加解锁 关键字比较的另一个锁机制 ReentrantLock 手动加解锁

synchronized与ReentrantLock区别点击此处

1.synchronized独占锁自动加锁和解锁,易操作,不灵活。
  ReentrantLock 独占锁,加锁和解锁需手动进行,且次数需一样,否则其他线程无法获取锁

2.synchronized 可重入锁,因为加锁和解锁自动进行,不必担心最后是否释放锁
  ReentrantLock 也可以重入,但加锁和解锁需手动进行,且次数一样,否则其他线程无法获取锁	

3.synchronized不可响应中断,一个线程获取不到锁就会一直等着,ReentrantLock可以响应中断。

4.ReentrantLock 可以实现公平锁机制(即访问中谁等待的时间最长谁的请求优先处理)

5.解决死锁问题通过tryLock设置超时等待时间

1.6 CopyOnWrite 写时复制容器
(即:当我们往一个容器里面添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器
,然后往新容器添加元素,添加完元素后,在将原容器的索引指向新的容器。(这样可以对CopyOnWrite容器进行并发的读
而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite 容器也是一种读写分离的思想),CopyOnWrite容器存在两个
问题,即内存占用问题和数据一致问题)
针对内存占用问题可以考虑 ConcurrentHashMap
1.7 java 多线程
并发和并行
并行: 指两个或多个事件在同一时刻发生(同时发生)
并行性使多个程序同一时刻可在不同cpu上同时执行。
并发: 指两个或多个事件在同一时间段内发生(不是真正的同时只是看上去同时) 在同一cpu上运行多个程序。
1.8 线程和进程
进程: 进程是正在运行的程序实例。
进程是线程的容器,即一个进程中可以开启多个线程。

     线程: 线程是进程内部的一个独立执行单元,一个进程可以同时并发运行多个线程;

1.9 线程创建的四种方式
1.继承Thread 类

import java.util.Date;

/**
 * 继承Thread写法
 */
public class MyThread  extends  Thread{

    @Override
    public void run() {
        for (int i=0;i<10;i++){
            System.out.println("myThread执行了:"+new Date().getTime());
        }
    }
}

class Test{
    public static void main(String[] args) {
        //1.创建自定义线程实例
        MyThread myThread = new MyThread();
        //2.启动线程
        myThread.start();
        //3.在main主线程打印信息
        try {
            Thread.sleep(1000);
            for (int i=0;i<10;i++){
                System.out.println("主线程执行了:"+ new Date().getTime());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}
     2.实现Runnable 接口
/**
 * 实现Runnable接口
 */
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            System.out.println(
       Thread.currentThread().getName()+"执行时间:"+new Date().getTime()+"执行次数!");
        }
    }
}

class TestRunnableDemo{
    public static void main(String[] args) {
        //1.主线程打印信息
        for (int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"执行时间");
        }
        //2.通过 thread 类执行Runnable 类
        Thread thread = new Thread(new MyRunnable(),"myRunnable");
        thread.start();
    }
}
     3.实现 Callable 接口
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        for (int i=0;i<10;i++){
            System.out.println("线程执行"+Thread.currentThread().getName());
        }
        return "MyCallable执行完毕";
    }
}
 class MyCallableTest{
    public static void main(String[] args) {
        //1.实现Callable接口
        //2.创建FutureTask实例,创建MyCallable实例
        FutureTask<String> task =  new FutureTask<>(new MyCallable());
        //3.创建Thread实例,执行FutureTask
        Thread thread = new Thread(task,"MyCallable");
        thread.start();
        //4.主线程打印信息
        for (int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"执行时间:"+new Date().getTime());
        }
        //获取MyCallable执行结果
        try {
            String result= task.get();
            System.out.println("结果是:"+result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }



}
     4.线程池	
public class MyRunnableTwo implements Runnable {

    @Override
    public void run() {

        for (int i=0;i<10;i++){
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName()+i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorServiceDemo {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        MyRunnableTwo runnableTwo = new MyRunnableTwo();
        executorService.execute(runnableTwo);

        for (int i=0;i<10;i++){
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName()+"主线程"+i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

2.0 线程池:
线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好的提高性能
,线程池在系统启动时创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行
这个任务,执行结束以后,改线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务

	  使用线程池的好处:
	      多线程运行时间,系统不断的启动和关闭新线程,成本非常高,会过渡的消耗系统资源,以及
		  过渡切换线程的危险,从而可能导致系统资源的崩溃

2.1 线程通讯方式:
休眠唤醒方式:
Object 的 wait,notify,notifyAll
Condition 的 await,signal ,signalAll
CountDownLatch : 用于某个线程A等待若干个其他线程执行完之后,它才执行
CyclicBarrier: 一组线程等待某个状态之后再全部同时执行
Semaphore: 用于控制对某组资源的访问权限
2.2 sleep 和 wait 区别
(1.) sleep 是线程中的方法,但是wait是Object中的方法
(2.)sleep 方法不会释放锁 ,但是wait会释放,而且会加入到等待队列中
(3.)sleep 方法不依赖于同步器 synchronized,但是wait需要依赖synchronized关键字
(4.) sleep 不需要被唤醒(休眠之后退出阻塞),但wait 需要
2.3 wait 和 notify
wait 和 notify 都是Object 中的方法
wait 和 notify 执行前线程都必须获得锁对象
wait 的作用 是使当前线程等待
notify 作用是通知其他等待当前线程的对象锁的线程
2.4 java 内存模型
jvm 内存共分为 虚拟机栈,堆,方法区,程序计数器,本地方法栈五个部分

 2.4.1程序计数器
	            每个线程对应有一个程序计数器。
			    各线程的程序计数器是私有的,互不影响,是线程安全的
			    程序计数器记录线程正在执行的内存地址,以便线程被中断恢复执行时再次按照中断时的指令继续执行
2.4.2 java 栈
			   每个线程会对应一个Java 栈
			   每个Java 栈由若干个栈帧组成
			   每个方法对应一个栈帧
			   栈帧在方法运行时,创建并入栈,方法执行完毕,该栈帧弹出栈帧中的元素作为该方法的返回值,该栈帧被清除
			   栈顶的栈帧叫活动栈,表示当前执行的方法,才可以被cpu执行
			   线程请求的栈深度大于虚拟机所允许的深度,将抛出 StackOverflowError异常
			   栈扩展时无法申请到足够的内存,就会抛出OutOfMemoryError 异常
2.4.3 方法区
			    方法区是java堆的永久区
				方法区存放了要加载的类的信息(名称,修饰符等)类的静态常量,类中定义为final类型的常量
				类中的Field信息,类中的方法信息
				方法区是被Java线程共享的
				方法区要是使用的内存超出其允许的大小时,会抛出OutOfMemoryError:PremGen space 的错误
 2.4.4常量池
			     常量池是方法区的一部分。
				 常量池中存储两类数据:字面量和引用量
				 字面量: 字符串,final 变量等
				 引用量:类/接口 ,方法和字段的名称和描述符
				 常量池在编译期间就被确定,并保存在已编译的.class 文件中
2.4.5 本地方法栈
			      本地栈和Java栈所发挥的作用非常相似,区别不过是Java栈为jvm执行Java方法服务
				   ,而本地方法栈为jvm执行的native方法服务
				   本地方法栈也会抛出StackOverflowError 和 OutOfMemoryError异常

2.6 线程安全问题
原因: 多个线程在操作共享数据
操作共享数据的代码有多条
多个线程对共享数据都有写操作

     线程不安全问题解决:线程同步
           要解决线程不安全问题, 只要在某个线程修改共享资源的时候,其他线程不能修改该资源,等待
		 修改完毕同步之后,才能去抢夺cpu资源,完成对应的操作,保证了数据的同步性。
     数据同步的七重机制
	    同步代码块(synchronized)
/**
 * 同步代码块
 */
public class TicketDemo  implements Runnable{
    private int ticketNum = 80 ; //电影票
    private Object obj = new Object();
    @Override
    public void run() {
        while (true){
            synchronized (obj){
                if (ticketNum>0){//判断是否还有票
                    //有票,让线程睡眠100毫秒 模拟售票
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //打印票
                    String name = Thread.currentThread().getName();
                    System.out.println("线程"+name+"销售电影票"+ticketNum--);
                }
            }
        }
    }

    public static void main(String[] args) {
        //1.创建电影票对象
        TicketDemo ticketDemo = new TicketDemo();
        //2.创建Thread对象,售卖电影票
        Thread thread =   new Thread(ticketDemo,"窗口1");
        thread.start();
        Thread thread2 =   new Thread(ticketDemo,"窗口2");
        thread2.start();
        Thread thread3 =   new Thread(ticketDemo,"窗口3");
        thread3.start();
    }
}
		同步方法(synchronized)
/**
 * 同步方法
 */
public class TicketDemo2 implements Runnable{

    private int ticketNum = 80 ; //电影票
    @Override
    public void run() {
        while (true){
            ticket();
        }
    }

    public synchronized void ticket(){
            if (ticketNum>0){//判断是否还有票
                //有票,让线程睡眠100毫秒 模拟售票
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //打印票
                String name = Thread.currentThread().getName();
                System.out.println("线程"+name+"销售电影票"+ticketNum--);
            }

    }

    public static void main(String[] args) {
        //1.创建电影票对象
        TicketDemo ticketDemo = new TicketDemo();
        //2.创建Thread对象,售卖电影票
        Thread thread =   new Thread(ticketDemo,"窗口1");
        thread.start();
        Thread thread2 =   new Thread(ticketDemo,"窗口2");
        thread2.start();
        Thread thread3 =   new Thread(ticketDemo,"窗口3");
        thread3.start();
    }
}

		同步锁(ReentrantLock)
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TicketDemo3 implements Runnable{

    private int ticketNum = 80 ; //电影票
    private Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
                lock.unlock();
                try{
                    if (ticketNum>0){//判断是否还有票
                        //有票,让线程睡眠100毫秒 模拟售票
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //打印票
                        String name = Thread.currentThread().getName();
                        System.out.println("线程"+name+"销售电影票"+ticketNum--);
                    }
                }finally {
                    lock.unlock();
                }
        }
    }

    public static void main(String[] args) {
        //1.创建电影票对象
        TicketDemo ticketDemo = new TicketDemo();
        //2.创建Thread对象,售卖电影票
        Thread thread =   new Thread(ticketDemo,"窗口1");
        thread.start();
        Thread thread2 =   new Thread(ticketDemo,"窗口2");
        thread2.start();
        Thread thread3 =   new Thread(ticketDemo,"窗口3");
        thread3.start();
    }
}

		特殊域变量(volatile)
		局部变量(ThreadLocal)
		阻塞队列(LinkedBlockingQueue)
		原子变量(Atomic*)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值