美文网首页
java基础2

java基础2

作者: 明鬼mio | 来源:发表于2019-12-25 14:08 被阅读0次
    1.如何实现list和数组相互转化:
    • 数组转List
      1).使用for循环将数组元素加入List中;
    List<String> list=new ArrayList<String>();
            for (String string : str) {
                list.add(string);
            }
    

    2).使用asList()方法,注意:asList()返回的列表大小是固定的,并且不是java.util.ArrayList类,而是定义在java.util.Arrays中一个私有静态类java.util.Arrays.ArrayList,这种情况,如果添加或者删除列表中的元素,程序会抛出异常

    List<String> list3 = Arrays.asList(str);
    

    3).使用Collections.addAll()

    List<String> list4=new ArrayList<String>(str.length);
            Collections.addAll(list4, str);
    

    4).使用Stream中的Collector收集器

    List<String> list5=Stream.of(str).collect(Collectors.toList());
    
    • List转数组
      1).使用for循环
    String[] str1=new String[list.size()];
            for(int i=0;i<list.size();i++) {
                str1[i]=list.get(i);
            }
            for (String string : str1) {
                System.out.println(string);
            }
    

    2).使用toArray()

    String[] str2=list.toArray(new String[list.size()]);
    
    2.Array和ArrayList区别
    • 存储内容:Array可以包含基本类型和对象类型,ArrayList只能包含对象类型。注意:Array数组在存放的时候一定是同种类型的元素;ArrayList就不一定了,因为ArrayList可以存储Object
    • 空间大小:Array大小是固定的,ArrayList的大小是动态变化的。
    • 方法:ArrayList提供了更多的方法和特性,比如:addAll(),removeAll(),iterator()等等。
    • 对于基本类型数据,集合使用自动装箱来减少编码工作量。但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢。
    • 基于效率和类型检验,应尽可能使用Array,无法确定数组大小时才使用ArrayList!不过当你试着解决更一般化的问题时,Array的功能就可能过于受限。
    3.迭代器Iterator
    • 迭代其实我们可以简单地理解为遍历,是一个标准化遍历各类容器里面的所有对象的方法类,它是一个很典型的设计模式。Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。
    4.并发和并行的区别
    • 并发(Concurrent),在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。
    • 并行(Parallel),当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。
    • 并发是指在一段时间内宏观上多个程序同时运行。并行指的是同一个时刻,多个任务确实真的在同时运行。
    • 并发的多个任务之间是互相抢占资源的;并行的多个任务之间是不互相抢占资源的。
    5.线程与进程的区别
    • 进程:是执行中一段程序,即一旦程序被载入到内存中并准备执行,它就是一个进程。进程是表示资源分配的的基本概念,又是调度运行的基本单位,是系统中的并发执行的单位。
    • 线程:单个进程中执行中每个任务就是一个线程。线程是进程中执行运算的最小单位。
    • 一个线程只能属于一个进程,但是一个进程可以拥有多个线程。多线程处理就是允许一个进程中在同一时刻执行多个任务。
    6.守护线程(Daemon Thread)
    • 只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。
    • Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。
    7.线程有哪些方式
    • 新建(NEW):新创建一个线程对象

    • 就绪:一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。

      处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由Java运行时系统的线程调度程序来调度的。

    • 运行状态(running):当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法。

    • 阻塞状态(blocked):线程运行过程中,可能由于各种原因进入阻塞状态:

      ①线程通过调用sleep方法进入睡眠状态;

      ②线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;

      ③线程试图得到一个锁,而该锁正被其他线程持有;

      ④线程在等待某个触发条件;

      所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。

    • 死亡状态(dead):有两个原因会导致线程死亡:

      ①run方法正常退出而自然死亡;

      ②一个未捕获的异常终止了run方法而使线程猝死;

      为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法,如果是可运行或被阻塞,这个方法返回true;如果线程仍旧是new状态且不是可运行的,或者线程死亡了,则返回false。


      image.png
    8.sleep()和wait()的区别
    • sleep() 方法是线程类(Thread)的静态方法,让调用线程进入睡眠状态,让出执行机会给其他线程,等到休眠时间结束后,线程进入就绪状态和其他线程一起竞争cpu的执行时间。
      因为sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep() 方法,线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象
      sleep可以在任何地方使用
    • wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程
      wait只能在同步控制方法或者同步控制块里面使用
    9.notify和notifyAll区别
    • 锁池和等待池
      锁池:假设线程a已经拥有某个对象的锁,而其他的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须获得该对象的锁的拥有权,但是该对象的锁目前正被线程a所拥有,所以这些线程就进入了该对象的锁池中
      等待池:假设一个线程a调用了某个对象的wait()方法,线程a就会释放giant对象的锁后,进入到该对象的等待池中,等待池中的线程不会去竞争该对象的锁
    • 区别:当有线程调用了该对象的notifyAll()方法(该方法唤醒所有wait线程)或者notify()方法(只随机唤醒一个wait线程),被唤醒的线程就会进入该对象的锁池中,锁池中的线程就会竞争该对象锁。即调用了notify后只有一个线程会由等待池进入锁池,而notifyAll会将该对象等待池中所有线程移动到锁池中,等待锁竞争
    • 永远在循环(loop)里调用 wait 和 notify,不是在 If 语句
    10.java创建线程池的方式
    • Executors目前提供了5种不同的线程池配置
    • 1.newCachedThreadPool(),它是用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置时间超过60秒,则被终止并移除缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用SynchronousQueue作为工作队列。
    • 2.newFixedThreadPool(int nThreads),重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有nThreads个工作线程是活动的。这意味着,如果任务数量超过了活动线程数目,将在工作队列中等待空闲线程出现;如果工作线程退出,将会有新的工作线程被创建,以补足指定数目nThreads。
    • 3.newSingleThreadExecutor(),它的特点在于工作线程数目限制为1,操作一个无界的工作队列,所以它保证了所有的任务都是被顺序执行,最多会有一个任务处于活动状态,并且不予许使用者改动线程池实例,因此可以避免改变线程数目。
    • 4.newSingleThreadScheduledExecutor()和newScheduledThreadPool(int corePoolSize),创建的是个ScheduledExecutorService,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程。
    • 5.newWorkStealingPool(int parallelism),这是一个经常被人忽略的线程池,Java 8 才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序。

    相关文章

      网友评论

          本文标题:java基础2

          本文链接:https://www.haomeiwen.com/subject/voefoctx.html