一、多线程
多线程可以并发执行多个任务
线程:一个顺序的单一的程序执行流程就是一个线程。代码一句一句的有先后顺序的执行。
多线程:多个单一顺序执行的流程并发运行。造成"感官上同时运行"的效果。
二、线程(Thread)的第一种创建方式:
1.继承Thread并重写run方法,在run()方法中定义需要并发执行的任务代码。
注意:启动线程要调用start方法,而非直接调用run方法,当调用start后线程便会纳入到线程调度器程序中统一被管理,一旦它被分配到了CPU的时间片就会开始自动执行它的run方法了。
2.优点:这种创建线程方式的优点是:结构简单,便于匿名内部类形式创建。
3.缺点:
1)由于java是单继承的,这导致如果继承了Thread就无法再继承其他类去复用方法,实际开发 中会造成很多不便。
2)定义线程时重写了run方法直接将任务定义在了线程中,导致线程与任务存在必然的耦合关系, 不利于线程的重用。
三、线程的第二种创建方式:
实现Runnable接口单独定义线程任务,然后创建Thread的有参构造对象来执行任务
四、main方法和currentThread()
1.java中所有的代码都是靠线程运行的,main方法也不例外,JVM启动后会创建一个线程来执行main方法. 并且该线程的名字也叫"main",因此我们通常称他为"主线程".但是它和我们创建的线程并无区别.
2.Thread提供了一个静态方法:
static Thread currentThread()
该方法可以获取运行这个方法的线程
五、getInetAddress().getHostAddress()获取客户端IP地址
通过socket获取远端计算机的地址信息
String host = socket.getInetAddress().getHostAddress()
六、获取线程相关信息的一些方法
1.String getName() 获取线程的名字
2.long getId() 获取线程的唯一标识
3.int getPriority() 获取线程优先级(1~10)
4.boolean isAlive() 线程是否还活着
5.boolean isDaemon() 线程是否为守护线程
6.boolean isInterrupted() 线程是否被中断了
七、线程的优先级
1.线程有10个优先级,分别对应整数1~10,其中1为最低优先级,10为最高优先级,5为默认值
2.线程start方法调用后便纳入到了线程调度器中统一管理,此时线程只能被动被分配时间片来并发运行。
线程不能主动索取时间片。调度器会尽可能均匀的将时间片分配给每一个线程。 修改线程的优先级可以最大程度改善获取时间片的次数。
原则上优先级越高的线程获取时间片的次数越多。
八、Block阻塞
sleep()方法
1.线程提供了一个静态方法:
static void sleep(long ms)
当一个线程调用sleep后就会进入阻塞状态指定的毫秒,超时后线程会自动回到RUNNABLE状态,再次开始并发运行
2.sleep方法要求必须处理中断异常。
当一个线程调用sleep方法处于睡眠阻塞的过程中,此时该线程的interrupt()方法被调用时会立即中断该睡眠的阻塞,并抛出中断异常
九、守护线程
Java将线程认为两类:用户线程和守护线程,也称为前台线程和后台线程。
守护线程是通过普通的用户线程通过调用setDaemon(true)设置而转变而来的,
因此创建和使用上与用户线程并无区别。但是主要区别在于:
进程的结束:当一个java进程中所有的用户线程都结束时,进程就会结束,此时会将所有的
守护线程全部杀死。
十、join方法:协调线程的同步运行
线程提供的方法:join可以协调线程的同步运行
多线程是并发运行,本身是一种异步运行状态。
同步运行:多个线程执行是存在了先后顺序。
异步运行:各自执行各自的。
注意:在方法中定义的类为局部内部类,局部内部类调用方法中的变量必须是final的
十一、多线程并发的安全问题
1.当多个线程并发操作同一临界资源,由于线程切换实际不确定,导致操作顺序出现混乱而引起各种逻辑错误。
临界资源:操作该资源的完整过程同一时刻只能由单线程进行
2.static yield()方法 --让出
该方法会停止该线程,回到Runnable再让线程调度器分配时间片
3.关键字synchronized --同步锁
当一个方法使用关键字synchronized后,该方法成为同步方法,即:
多个线程不能同时执行这个方法。
将多线程并发操作改为同步有先后顺序的排队执行可以有效解决并发安全问题
注:在方法上直接使用synchronized,那么同步监视器是不可选的,就是当前方法的所属对象this
4.同步块的应用(推荐)
有效的缩小同步范围内可以在保证并发安全的前提下尽可能的提高并发效率
语法:
synchronized(同步监视器对象){
需要多个线程同步执行的代码片段
}
同步块在使用时需要在“()”中指定同步监视器对象,该对象可以是任何引用类型的实例,只要保证多个需要同步执行该代码块的线程看到的这个对象是“同一个”即可,实际开发中可结合具体情况选取。
PS:通常情况下同步监视器对象抢谁锁谁
5.静态方法锁
如果我们在静态方法上使用synchronized,那么该方法就一定具有同步效果。
注:1)静态方法指定的锁对象为当前类的类对象,即:Class的实例
2)JVM在加载一个类时会实例化一个Class的实例与之对应,这个实例称为一个类的类对象。
在JVM内部每个被加载的类都有且只有一个Class的实例与之对应。静态方法指定的同步监视器对象也是它。
3)同步块中通常也是类对象,引用一个类的类对象格式为:类名.class
PS:后面学习java反射机制时会介绍Class
6.互斥锁(相同类创建一个对象,不同线程分别调用不同的同步方法时互斥)
当使用多个synchronized锁定多个代码片段,并且指定的锁对象(同步监视对象)相同时,那么这些代码片段之间就是互斥的,多个线程不能同时访问他们。
7.死锁(面试问题)
当多个线程都各自持有一个锁的同时等待对方先释放锁时就会形成一种僵持状态,这个状态我们称为死锁现象。