一.java多线程
1.线程的实现
- 进程:一个虚拟机就是一个进程
- 线程:一个线程是一个类,由主类进行开启,执行公共的业务逻辑代码。
- 使用场景:io、网络阻塞和非强制依赖(不需要同步)
- 创建:Thread实现了runnable接口,两种方式没有本质区别,都要重写run()方法,只是多态的问题
- 继承thread类:Mythread.start()启动,可用匿名内部类快速实现写法。
- 实现runnable:传入到Thread(实现类)构造器中然后使用thread1.start()启动。
- 线程安全问题:同一个对象的同一个实例变量的访问。
- web开发:servlet是单例的,请求线程访问必须是同步的。(所以尽量使用局部变量,实例变量只能是service层注入或一些工具类注入)
- 线程类的方法:
- Thread.currentThread().getname()返回当前调用此代码段的线程名。
- isAlive():返回是否存活(准备运行)状态
- Thred.sleep():释放cpu一段时间,终止线程。
- Thread.yield():立即释放时间片,没什么用,有可能立刻抢回来。
- getid():唯一标识
- setpriority():设置优先级,但并不是强制抢占时间片。
- 终止:
- stop():弃用、暴力终止会出现不可预期错误,对对象破坏不一致对其他线程可见。
- interrupt():只能打中断符号,需要配合手动抛异常或return退出。
- interrupted()和isinterrupted():判断当前线程是否中断,后者会清除该状态,所以应该在run()方法里判断可退出线程。
- 注意:sleep()和this.interrupt()只要在一起使用就会抛异常,wait和interrupt()也会抛异常,和join()在一起也会抛异常
- 暂停和恢复:
- suspend()和resume():弃用、因为暂停线程并且会锁住资源。
2.同步
- synchronized:对该方法进行加锁,即一个java进程中的线程不能同时调用该方法(从堆取加到栈中)。
- 原理:检查标记ACC,是一个对象锁,
- synchronized关键字:给非静态方法使用则默认添加本对象锁,且其他syn方法也无法访问
- 可重入锁:有对象锁就可以调用其他synchronized方法
- 代码块sycnchronized{}:可在方法内声明具体需要同步的代码,其他代码可以异步。
- class对象锁synchronized(class):给静态方法默认使用class锁。
- 解决死锁:
- 工具:jsp命令查看当前线程号——jstack查看线程状态
- volatile:声明一个变量为强制公共区域取值,否则则会从私有栈中取值。
- 应用:32位操作系统的double赋值,取最新值
- 缺点:变量volat i++是非原子的,因此得用synchronized
- 禁止重排序:对没有依赖关系代码jIT会重排序,但volatile变量不会允许赋值重排到后面。
3.通信和线程切换
- wait/notify通信:原始需要让线程sleep()和轮询while()相当于自旋锁,现在在同步块里定义qi
- 应用:解决经典生产者消费者问题
- wait():只能写在同步块
lock.wait
- 作用效果:暂停并释放锁,没有锁就抛异常,并发出通知。
- wait(long):等锁一段时间,没有自动醒,而且必须有锁
- notify():唤醒wait等待同一锁的所有队列的其中一个线程。
- 作用效果:会等当前同步块执行完再放锁。
- 状态
- 阻塞:等syn对象锁、wait()暂停、sleep()睡觉、
- runnable:获得锁、sleep()结束、获得notify()、io结束
- join():主线程中调用阻塞自身并开启线程,直到开启线程的销毁
- 作用:让主线程等子线程
- 特征:底层调用了wait(),会释放自身锁,别的线程能调用此线程同步方法。sleep不行。
- ThreadLocal:此对象能存储属于线程的私有数据
- set()原理:往Threadmap中存取数据,key就是Threadlocal对象,值为传入value。
- 作用:任一包的线程能访问threadmap并且存取数据。
- InheritableThreadLocal:父线程能访问子线程数据
二.concurrent
1.Atomic包
- 概念:实现一些同步变量的包。
- AtomicInteger(x):构造一个原子变量,相当于变量的syn
2.Locks包
- ReentrantLock:lock接口
- lock():获取锁,中间写同步代码块
- unlock():解锁
- getwaitqueuethreads():返回此锁相关等待线程数
- isfair():是否为公平锁,默认非公平
- Condition对象:比wait()通知机制好,具有灵活通知特点
- await():前提条件也是获得锁,相当于objec的wait()
- 底层是park方法,执行blocker方法。
- signal():相当于notify()
- await():前提条件也是获得锁,相当于objec的wait()
- ReadwriteLock:解决读锁排它性的问题
- readlock().lock():作用是获取读锁后,允许继续获得读锁,但不允许写锁进入。
- writelock().lock():作用相当于lock的互斥
3.concurrent包
- Callable:用法同runnable,可传泛型有返回值,并且能抛异常。
- call():
三.单例模式的多线程
1.饿汉模式
- 实现:通过初始化静态成员变量立即创建单例,并通过静态方法getInstance()获取
- 二、使用静态块初始化单例
- 线程安全:不能拥有实例化变量,因为非同步,
2.懒汉模式/延迟加载
- 实现:只初始化引用,通过静态方法getInstance()获取对象时再创建对象new SingleInstance
- 线程安全:有可能初次创建时就进入多个线程,出现多个实例。
- 解决:syn关键字法会严重降低效率。
- 双检查锁机制DCL:volatile保证对单例对象指针的共享,缩减syn代码块保证只有一个线程会创建对象。
- volatile必要性:创建对象禁止重排序。
- 用静态内部类也可以实现。
3.反序列化单例模式实现
- 实现:使用readresolve()方法返回。
本文作者为byzhj,转载请注明。