#
- synchronized同步方法,同步语句块
volatile关键字的主要作用是使变量在多个线程之间可见
ThreadLocal
类ThreadLocal主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据。
守护线程
在java中有两种线程,一种是用户线程,另一种是守护线程。
守护线程是一种特殊的线程,它的特性有”陪伴”的含义,当进程中不存在非守护线程了,则守护线程自动销毁。典型的守护线程就是垃圾回收线程,当进程中没有非守护线程了,则垃圾回收线程就没有存在的必要了,自动销毁。
volatile 关键字
关键字volatile的主要作用是使变量在多个线程间可见。
线程间通信机制
等待通知机制 wait/notify/interrupt
通过管道进行线程间通信
PipeInputStream/PipeOutputStream
PipeReader/PipeWriter
join的使用
在很多情况下,主线程创建并启动子线程,如果子线程中要进行大量的耗时运算,主线程往往将早于子线程结束之前结束。这时主线程想等待子线程执行完成之后再结束,比如子线程处理一个数据,主线程要取得这个数据中的值,就要用到join()方法了。方法join()的作用是等待线程对象销毁。
类ThreadLocal的使用
Lock
ReentrantLock类
JDK1.5中新增了ReentrantLock类也能达到类似synchronized关键字来实现线程间的同步互斥,扩展功能上更加强大
使用示例:
1
2
3
4
5Lock lock=new ReentrantLock();
...
lock.lock();
...
lock.unlock();
使用Condition实现等待/通知
类似synchronized与wait()/notify()/notifyAll()方法相结合可以实现等待/通知模式,类ReentrantLock借助于Condition对象也可以实现同样的功能,且具有更好的灵活性
Condition对象可以实现多路通知功能
在一个Lock对象里面可以创建多个Condition(即对象监视器)实例,同一个Lock锁可以创建多个Condition监视器,不同的线程使用不同的Condition监视器进行等待通知,可以有选择性地进行线程通知
公平锁和非公平锁
锁Lock分为”公平锁”和”非公平锁”,公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。而非公平锁就是一种获取锁的抢占机制,是随机获得锁的,和公平锁不一样的就是先来的不一定先得到锁,这个方式可能造成某些线程一直拿不到锁,结果也就是不公平的。(公平与不公平并不是绝对的,公平锁10个线程中可能有1个不按照FIFO规则,但大多数还是按照这个规则)。
Lock锁还有许多方法函数:
getHoldCount()、getQueueLength()、getWaitQueueLength()……
ReentrantReadWriteLock类
类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务,虽然线程安全但是效率低下,使用读写锁ReentrantReadWriteLock类,可以提升该方法代码运行速度。
读写锁表示有两个锁,一个是读操作相关的锁,称为共享锁;一个是写操作相关的锁,称为排他锁。多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。
示例:
1
2
3
4
5
6
7
8
9ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
...
lock.readLock().lock();
...
lock.readLock().unlock();
...
lock.writeLock().lock();
...
lock.writeLock().unlock();
定时器Timer的使用
- schedule(TimerTask task,Date time)
- schedule(TimerTask task,Date firstTime,long period)
- schedule(TimerTask task, long delay)
- schedule(TimerTask task, long delay, long period)
- scheduleAtFixedRate(TimerTask task,Date firstTime,long period)
单例模式与多线程
懒汉模式中,多线程环境中,”延迟加载”不能实现保持单例的状态,单纯地同步整个代码块会使效率降低或者无法保持单例,使用DCL双检查锁机制。
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16volatile static MyObject myObject;
...
public static MyObject getInstance(){
if(myObject!=null){
}else{
//模拟在创建对象之前做一些准备性的工作
Thread.sleep(3000);
synchronized(MyObject.class){
if(myObject==null){
myObject=new MyObject();
}
}
}
...
}
...还可以使用静态内置类实现单例模式
多线程的序列化和反序列化
需要添加readResolve()方法:
1
2
3
4
5...
protected Object readResolve(){
return MyObjectHandler.myObject;
}
...static代码块实现单例模式
静态代码块中的代码在使用的时候就已经执行了,所以可以应用静态代码块的这个特性来实现单例设计模式。
enum枚举数据类型实现单例模式
枚举enum和静态代码块的特性相似,在使用枚举类时,构造方法会被自动调用,也可以应用其这个特性实现单例设计模式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public enum MyObject{
connectionFactory;
private Connection connection;
private MyObject(){
try{
...
connection=DriverManager.getConnection(url,username,password);
}catch(...){
...
}
}
public Connection getConnection(){
return connection;
}
}
线程的状态
new、runnable、ready、running、timed waiting、waiting、blocked、terminated
线程组
可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程。这样的组织结构有些类似于树的形式。
SimpleDateFormat非线程安全
类SimpleDateFormat是非线程安全的
解决方案1:
1
2
3
4
5
6
7
8public class DateTools{
public static Date parse(String formatPattern,String dateString) throws ParseException{
return new SimpleDateFormat(formatPattern).parse(dateString);
}
public static String format(String formatPattern,Date date){
return new SImpleDateFormat(formatPattern).format(date).toString();
}
}解决处理错误的原理就是创建了多个SimpleDateFormat类的实例。
解决方案2:
ThreadLocal类能使线程绑定到指定的对象,使用该类也可以解决多线程环境下SimpleDateFormat类处理错误的情况
1
2
3
4
5
6
7
8
9
10
11
12public class DateTools{
private static ThreadLocalt1=new ThreadLocal ();
public static SimpleDateFormat getSimpleDateFormat(String datePattern){
SimpleDateFormat sdf=null;
sdf=t1.get();
if(sdf==null){
sdf=new SimpleDateFormat(datePattern);
t1.set(sdf);
}
return sdf;
}
}
线程中出现异常的处理
- 方法setUncaughtExceptionHandler()的作用时对指定的线程对象设置默认的异常处理器。
- 方法setDefaultUncaughtExceptionHandler()对所有线程对象设置异常处理器。