线程
要说线程,必须得先说进程,线程是依赖于进程存在的!
进程:能够调用系统资源的独立单位。
多进程的意义:为了提高CPU的使用率。比如多进程计算机,在打游戏的同时听音乐是同时进行的吗?答案不是同时的,只是感觉上是,CPU的一点点时间片在两个进程之间高效的来回切换。
线程:线程依赖于进程存在,线程是进程中某一个任务。
多线程的意义:为了让多个任务在互相抢占CPU的执行权;线程的执行具有随机性。
多线程面试题1
JVM是多线程的吗?
- JVM是多线程的,至少有两条线程
1)main方法:“用户线程"或者"主线程” ,JVM调用main方法
2)垃圾回收线程,在内存中不断的通过垃圾回收器释放空间
使用Java语言如何实现多线程环境?
- 实现多线程环境:
创建系统资源(产生进程)----->Java语言不能系统资源—>所以Jdk提供了一个类:
Thread类:是封装的线程类(里面一些功能的底层实现(C/C++语言)系统资源创建)Java 虚拟机允许应用程序并发地运行多个执行线程
实现方式1:—>继承关系
- 1)自定义类 继承自Thread类(线程类)
- 2)在当前自定义的类中:重写run方法 (执行耗时的操作)(jvm会自动的让子线程执行run方法)
- 3)在"用户线程"main ,创建该类对象
- 4)启动线程 (执行子线程)
多线程面试题2
-
新建状态
NEW----->等价 public static final …; -
线程就绪(等待执行)
RUNNABLE -
线程阻塞(线程睡眠…)
BLOCKED -
线程等待中 (线程在执行期间,利用wait()方法)(死死等待)
WAITING -
超时等待(超过一定时间,然后等待结束)
TIMED_WAITING
-
线程死亡
TERMINATED
线程的优先级
//线程的优先级: 也遵循线程的执行具有随机性!
//public static final int MAX_PRIORITY 10 :最大优先级 10
//public static final int MIN_PRIORITY 1 :最小优先级 1
//public static final int NORM_PRIORITY 5 :默认优先级 5
/*优先级越大的线程:抢占到CPU的执行权越大
越小的优先级的线程:抢占到CPU的执行权越小
默认的优先级:抢占到CPU的执行权相等的*/
//public final int getPriority():获取优先级
//public final void setPriority(int newPriority):设置优先级
newPriority : 1:最小优先级
5:默认的优先级
10:最大优先级
实现方式2
方式1是继承关系,继承关系具有弊端:局限性 ,继承当前Thread类重写run方法之后将Thread类中所有的公共的功能都继承过来了,不能体系扩展功能!
* 1)自定义一个类,实现Runnable接口(里面只有一个抽象方法)函数式接口
- 2)重写接口中的run方法,run方法中执行耗时的操作
- 3)在主线程(main)中,创建当前自定义类的对象(资源对象)
- 4)创建Thread类对象,将上面3)资源对象作为参数进行传递
Thread(Runnable target):创建线程类对象 不设置名称
Thread(Runnable target, String name):创建线程类对象同时设置线程名称
- 5)启动线程 start()方法
Java中的同步机制
- 解决线程安全问题的标准
1)程序是否是多线程环境 ;
2)是否有共享数据;
3)是否存在多条语句对共享数据的操作 。
解决方案
1,2)不能改动,首先需要使用多线程程序;
针对3)来进行改动,如果能够将多条语句多共享数据的操作包裹起来,形成一个代码块—解决这个问题:
- Java提供了专业名称:Java同步机制---->同步代码块 synchronized (同步锁(悲观锁))
//格式:
synchronized(锁对象){
多条语句对共享数据的操作;
}
- 注意锁对象:必须是同一个锁对象,否则不是同一把锁,还是会存在线程安全问题!
- 锁对象:可以是任意的Java类型(包含Object以及JDK提供的类或者自定类的对象)
同步方法
什么是同步方法?
如果一个方法的方法体就是一个同步代码块的话,将synchronzied关键字放到方法声明上
形式一个同步方法(非静态)
//格式:
权限修饰符 synchronized 返回值类型 方法名(形式参数){
....
}
同步方法的锁对象:是this 代表当前类对象的地址值引用!
静态的同步方法的锁对象:是当前类名.class属性(可以获取当前类的字节码文件对象 :Class)
JDK5以后提供了更具体的锁定操作,可以获取锁以及释放锁,它和synchronized用法一样,提供很多功能。
Lock 接口,不能实例化提供了,更具体的锁:可重入锁:ReentrantLock
- public void lock():获取锁
- public void unlock():试图释放该锁
Java中的等待唤醒机制 (使用锁对象调用wait()/notify())
生产消费者模式(管线法)
- 生产者线程:生产者线程不断的产生数据,当没有数据,等待产生数据,通知(notify())消费者线程使用数据;
- 消费者线程:消费者不断的使用数据,当有数据了,等待消费掉,如果没有数据了,通知(notify())生产者线程产生数据。
sleep和wait()方法的区别?
1)来源不同
sleep()来源于Thread类
wait()来源于Object类 ----->跟锁对象有关系!
2)是否会释放锁:
sleep(long time)调用不会释放锁,暂定执行,当前睡眠到了,又重新开始运行!
wait():调用时,会立即释放锁,使用notify()唤醒对方线程,解决死锁问题!
3)共同点:
这两个方法都会抛出异常:InterruptedException:中断
都属于阻塞式方法;
多线程实现方式3—>线程池
线程池:(ExceutorService)
-
特点:
线程池:产生一个固定的可重用的线程数,线程对象创建完毕并且执行完毕,不会被 GC回收掉,而是将该线程对象再次归还到线程池中,等待下次重复利用!
数据库连接池(第三方的东西:阿里巴巴 druid:德鲁伊 /c3p0):产生一个固定的可用的连接池,记录最大的链接数量是多个,记录最小的链接数是多少个,一旦超出了最大连接数量,将这里面某一个连接对象colse()掉,归还到连接池中! -
无论线程池还是连接池弊端,使用成本要比传统的的开启子线程成本大!
ExecutorService:接口 线程池:如何实例化?
不能直接实例化,所以提供工厂类:Executors
public static ExecutorService newFixedThreadPool(int nThreads):创建固定的可重用的线程数的线程池!
ExecutorService 的API:
- 提交异步任务:
- Future submit(Callable task)
- Callable:异步任务接口 :
- 有一个抽象方法:V call() throws Exception:具体计算结果值
- Future submit(Runnable task,T result)
- Future:接口:表示异步任务计算的结果
- void shutdown() :将之前提交的异步任务按照顺序关闭!