1.什么进程?
* 值得就是正在运行的程序,是系统进行资源分配和调用的独立单位
* 每一个进程都有它自己的内存空间和系统资源
2.什么线程?
* 是进程中的每个顺序控制流,是一条执行路径
* 一个进行如果只有一条执行流程,则为单线程
* 一个进程有多条执行路径,则为多线程
3.什么是并行?什么是并发?
* 前者是逻辑上同时发生,指在某一个时间内同时运行的多个程序
* 后者是物理上同时发生,指在某一个时间内同时运行多个程序
4.java的运行原理?
* 由java命令启动JVM,JVM启动就相当于启动了一个进程
* 接着该进程创建了一个主线程去调用main()方法
5.需求:我们要实现多线程的一个程序,问 我们要如何进行实现?
* 由于线程是依赖进程而 存在的,所以我们应该先创建一个进程出来,
* 而进程是由系统进行创建的,所以我们应该去调用系统工程,创建一个进程
* java是不能直接去调用系统功能的,所以我们没办法直接实现多线程的程序
* 但是呢,java可以去调用C/C++写好的程序来实现多线程的
* 由C/C++去调用系统功能创建进程,然后由java去调用这个方法
继承Thread类 步骤:
1.自定义MyThread,继承Thread类
2.在MyThread中重写run()方法
为什么要重写run()方法?
不是类中的所有代码都需要被线程去执行的.
而这个时候呢,为了区分哪些代码能够被线程执行。java中提供了Thread类中的run()
用来包含哪些被线程执行的代码
3.创建对象
4.启动线程
run() 他是一个单线程,直接可以当做普通方法去使用,
如果我想 执行一个多线程 那么另一个方法 start()
问 start()和run的区别?
run()仅仅是封装线程执行的代码,直接调用时可以是 一个普通的方法
start()首先启动了进程,然后由jvm去调用该线程的run()方法
Thread类的基本获取和设置线程的方法:
1.public final String getName() 获取线程的对象名称
2.public final void setName(String name):设置线程的名称
我们也可以通过构造方法去给线程起名称
问:
如果获取了main方法所在的线程名称?
例如:针对如果不是Thread类的子类中如何获取线程名称对象呢?
1public static Thread curretThread() 返回当前正在执行的线程名称
2.Thread.curretThread().getName()
我们要获取main()方法 所在的线程对象名称 如何解决?
//遇到这种情况呢,Thread类提供了一个很好玩的方法
1.public static Thread currentThread() 返回当前正在执行的线程对象
线程的调度
假如我们的计算机只有一个cpu,那么CPU在某一个时刻只能执行一条指令
线程只有得到CPU时间片才能有使用权,才能执行指令
线程的两种调度策略
1.分时调度策略: 所有线程轮流的去使用CPU的使用权,平均进行分配,每个线程占用CPU的时间
2.抢占式调度策略:优先让级别高的线程使用CPU,如果线程的优先级相同,那么他们会随机选择一个,优先级高的线程获取CPU
时间片的调度策略会多一些.
注意:java中用的就是抢占式调度模型
优先级我们的线程是没有设置优先级的,肯定是有默认的优先级,
在java中默认的优先级是5
线程优先级的范围:1-10
线程优先级仅仅表示线程获取的CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看见更好的效果
设置线程优先级的方法?
public final void serPRriority(int NewPriority) : 更改线程对的优先级
线程的睡眠方法:
public static void sleep(long milis):在指定的毫秒数内让当前正在执行的线程休眠(暂停一会再去执行)
注意:
在sleep中 传入值是毫秒值
线程的加入方法:
1.public final void join():等待该线程或者终止
大体的概念:
我调用了这个方法,必须线程执行完毕之后,其他的线程才能调用
线程的中断与结束方法:
public final stop():让线程停止,过时间了,但是还可以使用
public void interrupt():中断线程,把线程装填停止,并抛出一个INTERRUPTEDEXCEPTION
创建线程的另一种方法 Runnable接口的类,该类也会去实现run()方法,然后可以分配该类的实例,
实现Runnable接口实现Runnable接口的好处:
1.可以避免由于JAVA当继承带来的局限性
2.适合多个相同的程序的代码去处理同一个资源的问题,把线程同程序的代码、数据有效的进行分离,较好的体现了面向对象的设计思想
实现Runable接口的步骤
1.定义一个MyRunnable,实现Runable接口
2.在MyRunnable中重写run()方法
3.创建MyRunnable类的对象
4.创建Thread类的对象,把MyRunnable对象作为构造方法的参数
5.启动线程
使用Runnable接口的好处:
不影响MyRunnable继承其他的类
同步锁的弊端1.效率比较低
2.容易产生死锁
例如:
两个或者两个以上的线程在争夺资源的过程中,发生了一种互相等待的现象
举例:
中国人、美国人吃饭案例
正常情况下:
中国人:一双筷子
美国人:一个刀一个叉
现在的问题:
中国人:一只筷子 一个刀
美国人:一只筷子 一个叉
线程之间的通信:
针对同一个资源的操作有不同种类的类型
只出不进:电影院卖票(八佰、金刚川)
可进可出:早餐店(生产者:厨师 消费者:顾客)
Lock锁背景 :
虽然我们可以理解同步代码块和同步方法的所对象,但是我们并没有看见那块上了锁,并在哪里释放了锁
为了更好更清晰的表达如何并如何释放锁,JDK5之后提供了一个新的锁对象,LOCK
lock是接口不能直接序列化,这里采用他的实现类ReentrantLock来实例化
方法ReentrantLock创建一个ReentrantLock的实例
加锁解锁的方法:
方法名 说明
void lock() 获得锁
void unlock() 释放锁
线程池线程池的基本背景
程序启动一个新的线程成本是很高的,因为它涉及到与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是
当程序中要创建大量的生存很短的线程时,就要考虑使用线程池
线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中称为空闲状态,等待下一个对象来使用
java内置支持线程池
线程是使用进程的资源,所以每次开启一个线程,它的成本是比较高的,所以使用线程池,就能解决这个问题
如何使用线程池?
Executors工厂来产生线程池,如一下几个方法
1.public static ExecutorService newCachedThreadPool()开启具有缓存功能的线程池
2.public static ExecutorService newFixedThreadPool(int nThreads) 创建爱你多少个线程池
3.public static ExecutorService newSingleThreadExecutor()创建单个的线程池
这些方法的返回值是ExecutorService对象,该对象表示一个线程池..可以执行Runnable对象或者Callable对象代表的线程.
步骤:
1.创建线程池对象
2.创建Runnable实例
3.提交Runnable实例
4..关闭线程池
线程池的好处
线程池里面的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲装填,等待下一个对象来使用
实现Callable接口好处
1.可以有返回值
2.可以抛出异常
弊端
代码比较复杂,所以一般不用