本文是《java多线程编程核心技术》第一、二章的学习笔记。
第一章:Java多线程技能
使用多线程
- 实现多线程有两种方式:继承
Thread
类、实现Runnable
接口 Thread.java
中的start()
方法是异步执行,thread.run
是同步;而且start()
方法的顺序不代表线程启动的顺序,它是随机的。- 在方法前加
synchronized
可以让线程安全。
一些方法
currentThread()
返回代码段正在被哪个线程调用isAlive()
判断当前线程是否处于活动状态sleep()
让线程休眠getID()
获得线程的唯一标志yield()
让当前线程放弃cpu资源,但时间不确定
停止线程
方式:
- 使用退出标识,使线程正常退出,也就是当run方法完成后线程退出
- 使用interrupt方法中断线程
第二种方式要注意:
interrupt()
实例方法,让线程中断,再用异常法检测中断使程序停止interrupted()
是静态方法,测试当前线程是否已经是中断状态,执行后具有将状态标志清除为false的功能。isInterrupted()
是实例方法,测试Thread对象是否已经是中断状态,但不清除状态标志。- 如果在sleep状态下停止某一线程,会进入catch语句(不需要判断是否中断),并且清除停止状态,使它变为false.
线程的优先级
getPriority()
查看优先级,setPriority()
设置优先级,有1~10级
线程优先级的特点:
- 继承性: 如过线程A启动线程B,则B和A优先级一样
- 规则性: CPU尽量倾向于把资源优先级高的线程
- 随机性: 优先级不等同于执行顺序,优先级较高的不一定先执行完
守护线程
Java的线程分为两种:User Thread(用户线程)、Daemon Thread(守护线程)。
当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。Daemon作用是为其他线程提供便利服务,守护线程最典型的应用就是GC(垃圾回收器),它就是一个很称职的守护者。
第二章:对象及变量的并发访问
synchronized同步方法
- 方法内的变量为线程安全,而实例变量非线程安全。
- 不同线程调用同一对象里的synchronized方法时,是同步的(排队进行)。也就是必须等线程执行完
synchronized
方法时,下一线程才能执行synchronized
方法。 - 可重入锁: 一个线程得到对象锁后,再次请求此对象锁时是可以得到该对象的锁的。子类也可以调用父类的同步方法。
- 出现异常,锁自动释放
- 子类方法不会继承
synchronized
关键字,需要手动在子类方法中加上。
synchronized同步语句块
- 多个线程处理同一个对象的
synchronized(this)
同步语句块时,只能排队执行 - 同一个对象的
synchronized(this)
和synchronized
同步方法之间也是同步的。即同一时间只有一个线程可执行synchronized代码块或方法中的代码 synchronized(非this对象x)
,是将x对象作为“对象监视器”- 当多个线程同时执行
synchronized(x){}
同步代码块时呈同步效果 - 当其他线程执行x对象中
synchronizd
同步方法时呈同步效果 - 当其他线程执行x对象方法里的
synchronized(this)
代码块时呈同步效果
- 当多个线程同时执行
- 静态同步
synchronized
方法与synchronized(class)
代码块是对Class类进行持锁。 - 当线程在等带根本不可能被释放的锁是,就会出现死锁。
- 如果同时持有相同的锁对象,线程之间就是同步的。注意对象的属性改变,运行结果还是同步的。
volatile关键字
volatile
: 强制的从公共内存进行取值,而不是从线程私有数据栈中取得变量的值。可以使变量在多个线程间可见,但缺点是不支持原子性。
synchronized
和volatile
比较:
- 关键字volatile是线程同步的轻量级实现,所以volatile性能比synchronized好,并且volatile只能修饰变量,而synchronized可修饰方法和代码块。
- 多线程访问volatile不会发生阻塞,而synchronized会出现阻塞
- volatile能保证数据可见性,不保证原子性;synchronized可以保证原子性,也可以间接保证可见性,因为synchronized会将私有内存和公共内存中的数据做同步。
- volatile解决的是变量在多个线程间的可见性,synchronized解决的是多个线程访问资源的同步性(互斥加可见)。
原子类:
如AtomicBoolean
,AtomicInteger
,AtomicLong
等。一个原子类型就是一个原子操作可用的类型,可在没有锁的情况下做到线程安全。但原子类的方法间的调用却不是原子的,需要用同步。