------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
多线程
在日常生活中,有很多事情是同时进行的,例如,人可以同时进行呼吸,血液循环,思考问题等。在使用计算机的过程中,不同的程序块也是可以同时进行的,这种多个程序块同时运行的现象被称作并发执行
定义:就是应用程序有多条执行路径。
进程: 就是正在运行的程序。
线程:就是进程的执行路径,执行单元。
如何使用多线程程序:
A:方式1 继承Thread类。
a:创建类继承Thread类
b:重写Thread类的run()方法。
run()方法里面才是封装线程的代码。
c:通过调用start()方法启动线程并调用run()方法。
代码体现:
B:方式2 实现Runnable接口
a:创建一个类实现Runnable接口
b:重写run()方法
c:创建实现类对象,并把它作为参数传递给Thread类的构造方法,创建Thread对象
d:通过Thread的对象调用run()方法
代码体现:
我的总结:第二种方法避免了Java单继承带来的局限性,一般用第二种方法
线程的随机性原理
多个程序其实是CPU的在做着高效切换执行的。
线程的生命周期
新建:创建一个线程对象后,该对象就处于新建状态,此时它不能运行,和其他Java对象一样,仅仅有Java虚拟机为其分配了内存,没有表现出任何线程的动态特征
就绪:当对象调用了start()方法后,该线程就进入就绪状态(也称为可运行状态)。处于就绪状态的线程位于可运行池中,此时它只是具备了运行条件,能否获得CPU的使用权开始运行,还需要等待系统的调度
运行:如果处于就绪状态的线程获得了CPU的使用权,开始执行run()方法中的线程执行体,则该线程处于运行状态
阻塞:一个正在执行的线程在某些特殊情况下,如执行耗时的输入和输出操作时,会放弃CPU的使用权进入阻塞状态
死亡:线程的run()方法正常执行完毕或者线程抛出一个为捕获的异常,错误,线程就进入死亡状态。
线程安全问题
导致安全问题的出现的原因:
多个线程访问出现延迟。
线程随机性。
买票例子:
输出:这样的话,会出现买了第0,甚至-1张票的情况!
我的总结:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
线程安全问题的解决方案:
A:同步代码块
synchronized(锁对象)
{
被同步的代码
}
B:同步方法
把synchronized加在方法上。
我的总结:一般使用同步代码块
线程间的通信问题
有一个数据存储空间,划分为两部分,一部分用于存储人的姓名,另一部分用于存储人的性别;
我们的应用包含两个线程,一个线程不停向数据存储空间添加数据(生产者),另一个线程从数据空间取出数据(消费者);
因为线程的不确定性,存在于以下两种情况:
若生产者线程刚向存储空间添加了人的姓名还没添加人的性别,CPU就切换到了消费者线程,消费者线程把姓名和上一个人的性别联系到一起;
生产者放了若干数据,消费者才开始取数据,或者是消费者取完一个数据,还没等到生产者放入新的数据,又重复的取出已取过的数据;
wait():让当前线程放弃监视器进入等待,直到其他线程调用同一个监视器并调用notify()或notifyAll()为止。
notify():唤醒在同一对象监听器中调用wait方法的第一个线程。
notifyAll():唤醒在同一对象监听器中调用wait方法的所有线程。
这三个方法只能让同步监听器调用:
在同步方法中: 谁调用
在同步代码块中: 谁调用
wait()、notify()、notifyAll(),这三个方法属于Object 不属于 Thread,这三个方法必须由同步监视对象来调用,两种情况:
1.synchronized修饰的方法,因为该类的默认实例(this)就是同步监视器,所以可以在同步方法中调用这三个方法;
2.synchronized修饰的同步代码块,同步监视器是括号里的对象,所以必须使用该对象调用这三个方法;
可要是我们使用的是Lock对象来保证同步的,系统中不存在隐式的同步监视器对象,那么就不能使用者三个方法了,那该咋办呢?
此时,Lock代替了同步方法或同步代码块,Condition代替了同步监视器的功能;
Condition对象通过Lock对象的newCondition()方法创建;
里面方法包括:
await(): 等价于同步监听器的wait()方法;
signal():等价于同步监听器的notify()方法;
signalAll():等价于同步监听器的notifyAll()方法;
线程的优先级
在应用程序中,如果要对线程进行调度,最直接的方式就是设置线程的优先级。优先级越高的线程获得CPU执行的机会越大,而优先级越低的线程获得CPU执行的机会越小。线程的优先级可以用1-10直接的整数来表示。数字越大,优先级越高。除了可以直接使用数字表示还可以使用Thread类中提供的三个静态常量来表示
static int MAX_PRIORITY 表示线程的最高优先级,相当于10
static int MIN _PRIORITY 表示线程的最低优先级,相当于5
static int NORM_PRIORITY 表示线程的最普通优先级,相当于5
方法 setPriority(int newPriority)可以对线程的优先级进行设置
线程的休眠
通过调用静态方法sleep(long millis)人为的控制线程,使整再执行的线程暂停将CPU让给别的线程
加入线程
新方法
thread类下 public final void join():
等待该线程终止。
需要注意
在加入某个线程之前要先启动这个线程
它的效果
一旦有join()线程,那么,当前线程必须等待,直到该线程结束。
用法
当其他线程需要等到某个线程执行完毕的时候才能执行这个时候可以用到这个方法。
它的效果
一旦有join()线程,那么,当前线程必须等待,直到该线程结束。
用法
当其他线程需要等到某个线程执行完毕的时候才能执行这个时候可以用到这个方法。
守护线程
main方法解析
main方法本身就是一个线程。
main方法是程序的入口,程序想执行必须通过主方法也就是main方法
新方法
public final void setDaemon(boolean on)://Thread方法下的
设置线程为守护线程,一旦前台(主线程),结束,守护线程就结束了。
新方法
public final void setDaemon(boolean on)://Thread方法下的
设置线程为守护线程,一旦前台(主线程),结束,守护线程就结束了。
线程的死锁问题
程序中两个线程下运行时都在等待对方的锁,这样便造成了程序的停滞,这种现象称为死锁
什么时候考虑用同步方法的方式锁呢?
当一个方法中所有的代码都需要锁的时候
什么时候考虑用同步代码块的方式锁呢?
当一个方法中不是所有代码都需要锁
静态方法的锁对象是谁呢?
1、是当前类的字节码文件对象。
当前类类名.class- Class类型的对象
2、静态方法其实就是方法声明是静态的
测试不同同步机制的锁对象
1、同步代码块的锁对象是什么?
1、同步代码块中的锁可以是任意对象包括this
2、同步代码块其实就是把synchronized加在方法中
2、同步方法的锁对象是谁?
1、就是this对象
2、同步方法其实就是就是把synchronized加在方法上
举例:private synchronized void check() {}
加在返回值类型的前面即可。
3、静态方法的锁对象是谁呢?
1、是当前类的字节码文件对象。
当前类类名.class- Class类型的对象
2、静态方法其实就是方法声明是静态的
什么时候考虑用同步代码块的方式锁呢?
当一个方法中不是所有代码都需要锁
什么时候考虑用同步方法的方式锁呢?
当一个方法中所有的代码都需要锁的时候