• 已删除用户
Administrator
发布于 2021-06-16 / 693 阅读
0

Java多线程编程核心技术二

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;
    }
}