第三部分 Java SE基础
3.1 java多线程
3.1.1 线程的实现方式,怎么启动线程怎么区分线程?
1.线程的实现方式:
有 4 种方式可以用来创建线程:
2.继承 Thread 类 2.实现 Runnable 接口 3.应用程序可以使用 Executor 框架来创建线程池 4. 实现 Callable 接口
实现 Runnable 接口比继承 Thread 类所具有的优势:
1)适合多个相同的程序代码的线程去处理同一个资源
2)可以避免 java 中的单继承的限制
3)增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
4)线程池只能放入实现 Runable 或 callable 类线程,不能直接放入继承 Thread 的类
5)runnable 实现线程可以对线程进行复用,因为 runnable 是轻量级的对象,重复 new 不会耗费太大资源,而 Thread 则不然,它是重量级对象,而且线程执行完就完了,无法再次利用。
3.怎么启动?
Thread thread=new Thread (继承了Thread的对象/实现了runnable的对象)
thread.setName("xxx");
thread.start();
启动线程使用start方法,而启动后执行的是run方法。
4. 线程状态
5.怎么区分线程?
假如在一个系统中有很多线程,每个线程都会打印日志,我想区分是哪个线程打印的,怎么办?
在创建线程时,thread.setName("设置一个线程名称");
这是一种规范,在创建完线程后,都需要设置。
6.中断线程
中断线程有很多方法:(1)使用退出标志,使线程正常退出,也就是当 run 方法完成后线程终止。 (2)通过 return 退出 run 方法
(3)通过对有些状态中断抛异常退出thread.interrupt() 中断。 (4)使用 stop 方法强行终止线程(过期)
中断线程可能出现的问题:
使用:Thread.interrupt()并不能使得线程被中断,线程还是会执行。最靠谱的方法就是
设置一个全局的标记位,然后再 Thread 中去检查这个标记位,发现标记位改变则中断线程。
3.2 线程并发库和线程池的作用?
JDKS中增加了Douglea的并发库,这一引进给Java线程的管理和使用提供了强大的便利性。
java.util.current包中提供了对线程优化,管理的各项操作,使得线程的使用变得得心应手。该包提供了线程的运行,线程池的创建,线程生命周期的控制。
Java通过Executors提供四种静态方法创建线程池,分别为:
1.newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
2.newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3.newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。
4.newSingleThreadExecutor创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行。
线程池的作用?
1.限定线程的个数,不会导致由于线程过多导致系统运行缓慢或崩溃。
2.控制线程池的并发数
3.线程池的重用
线程的创建和销毁的开销是巨大的,而通过线程池的重用大大减少了这些不必要的开销,当然既然少了这么多消费内存的开销,其线程执行速度也是突飞猛进的提升。
4.线程池可以对线程进行管理
线程池可以提供定时、定期、单线程、并发数控制等功能。比如通过ScheduledThreadPool线程池来执行S秒后,每隔N秒执行一次的任务。
3.3 一般线程和守护线程的区别
所谓守护线程是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称职的守护者,并且这种线程并不属于程序中不可或缺的部分。因 此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。
区别:唯一的区别是判断虚拟机(JVM)何时离开,Daemon 是为其他线程提供服务,如果全部的 User Thread 已经撤离,Daemon 没有可服务的线程,JVM 撤离。也可以理解为守护线程是 JVM 自动创建的线程(但不一定),用户线程是程序创建的线程;比如 JVM的垃圾回收线程是一个守护线程,当所有线程已经撤离,不再产生垃圾,守护线程自然就没事可干了,当垃圾回收线程是 Java 虚拟机上仅剩的线程时,Java 虚拟机会自动离开。
在使用守护线程时需要注意一下几点:
(1) thread.setDaemon(true)必须在 thread.start()之前设置,否则会跑出一个IllegalThreadStateException 异常。你不能把正在运行的常规线程设置为守护线程。
(2) 在 Daemon 线程中产生的新线程也是 Daemon 的。
(3) 守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。