Java多线程编程核心技术二
四、Lock的使用
4.1使用ReentrantLock类
public class MyService{
private Lock lock=new ReentrantLock();
public void testMethod(){
lock.lock();
for(int i=0;i<5;i++){
System.out.println("ThreadName="+Thread.currentThread().getName()+(""+(i+1)));
}
lock.unlock();
}
}
4.1.1使用Condition实现等待/通知
public class MyService{
private Lock lock=new ReentrantLock();
public Condition condition=lock.newCondition();
public void wait(){
try{
lock.lock();
System.out.println("await时间为"+System.currentTimeMillis());
//睡眠
condition.await;
}catch(InterruptException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
public void signal(){
try{
lock.lock();
System.out.println("signal时间为"+System.currentMillis());
//唤醒
condition.signal();
}finally{
lock.unlock();
}
}
}
4.1.2公平锁和非公平锁
公平与非公平锁:锁lock分为“公平锁”和“非公平锁”,公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。而非公平锁就是一种获取锁的抢占机制,是随机获得锁的。新建lock对象时,通过传入一个boolean参数,区分公平和非公平,默认非公平。
4.2使用ReentrantReadWriteLock类
类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务,这样做保证了实例变量的线程安全性,但效果确是非常低下的。
类ReentrantReadWriteLock读写锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也叫排他锁。也就是多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。
五、定时器
Timer类的主要作用就是设置计划任务,但封装任务的类却是TimerTask类,执行计划任务要放入TimerTask的子类中,因为TimerTask是一个抽象类;
public class Timer1 {
private static Timer timer =new Timer(true);
public static TimerTask tt=new TimerTask(){
@Override
public void run() {
System.out.println("这就是你将要执行的任务。。。");
}
};
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dataString="2020-11-26 15:31:00";
Date parse = sdf.parse(dataString);
System.out.println("字符串时间:"+parse.toLocaleString());
timer.schedule(tt,parse);
}
}
六、单例模式与多线程
6.1饿汉模式
//静态变量,在类初始化时,就已经实例化了
public class MyObject{
//立即加载方式==饿汉模式
private static MyObject myObject=new MyObject();
private MyObject(){}
public static MyObject getInstance(){
//此版本为立即加载
//缺点是不能有其他实例变量
return myObject;
}
}
6.2懒汉模式
//延迟加载,在调用方法时实例才被创建
public class MyObject{
private MyObject(){}
private static MyObject myObject;
public static MyObject getInstance(){
//延迟加载
if(myObject==null){
myObject=new MyObject;
}
return myObject;
}
}
缺点:在多线程环境下,懒汉模式并不能保证单例
//声明synchronized关键字
public class MyObject{
private MyObject(){}
private static MyObject myObject;
//整个方法上锁,效率太低
synchronized public static MyObject getInstance(){
//延迟加载
if(myObject==null){
myObject=new MyObject;
}
return myObject;
}
}
//DCL双重检查锁
public class MyObject{
private MyObject(){}
private static MyObject myObject;
//整个方法上锁,效率太低
public static MyObject getInstance(){
//延迟加载
if(myObject==null){
synchronized(this){
if(myObject==null){
myObject=new MyObject;
}
}
}
return myObject;
}
}
6.3使用静态内部类实现单例模式
public class MyObject{
private MyObject(){}
private static class MyObjectHandler{
private static MyObject myObject=new MyObject();
}
public static MyObject getInstance(){
return MyObjectHandler.myObject;
}
}
6.4序列化与反序列化的单例模式实现
上述方式,如果遇到序列化对象时,结果还是多例,需要做如下改造:
public class MyObject{
private MyObject(){}
private static class MyObjectHandler{
private static MyObject myObject=new MyObject();
}
public static MyObject getInstance(){
return MyObjectHandler.myObject;
}
protected Object readResolve() throws ObjectStreamException{
System.out.println("调用了readResolve方法");
return MyObjectHandler.myObject;
}
}
6.5使用static代码块实现单例模式
public class MyObject{
private static MyObject myObject;
private MyObject(){}
static{
myObject=new MyObject();
}
public static MyObject getInstance(){
return myObject;
}
}
6.6使用enum枚举数据类型实现单例模式
枚举enum和静态代码块的特性相似,在使用枚举类时,构造方法会被自动调用,也可以应用这个特性实现单例设计模式;
class Resource{
}
public enum SomeThing {
INSTANCE;
private Resource instance;
private SomeThing() {
instance = new Resource();
}
public Resource getInstance() {
return instance;
}
}