并发编程基础知识二

volatile关键字的作用是变量在多个线程之间可见
volatile的作用是强制线程到主内存(共享内存)里读取变量,而不是线程工作内存区里去读取变量,从而实现了多个线程之间的变量可见,也就是满足线程安全的可见性。

    private volatile boolean isRunning = true;
    private void setRunning(boolean isRunning){
        this.isRunning = isRunning;
    }
    
    public void run(){
        System.out.println("进入run方法..");
        int i = 0;
        while(isRunning == true){
            //..
        }
        System.out.println("线程停止");
    }

volatile 关键字虽然拥有多个线程之间的可见性,但是却不具备原子性
volatile关键字用于针对多个线程可变的变量操作,但是不能替代synchronized关键字的同步功能。


atomic类支持原子性操作

    private static AtomicInteger count = new AtomicInteger(0);
    
    
    /**synchronized*/
    public synchronized int multiAdd(){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count.addAndGet(1);
            count.addAndGet(2);
            count.addAndGet(3);
            count.addAndGet(4); //+10
            return count.get();
    }

多个addAndGet在一个方法内是非原子性的,需要加synchronized进行修饰,保证4个addAndGet整体原子性


线程通信
使用wait和notify可以实现线程之间的通信

  1. wait/notify必须配合synchronized 关键字使用
  2. wait释放锁 notify不释放锁
  3. 所有的object都可以使用该方法
   // final Object lock = new Object();
    final CountDownLatch countDownLatch = new CountDownLatch(1);
    
    Thread t1 = new Thread(new Runnable() {
    
            public void run() {

                //synchronized (lock) {
                    try {
                        
                        //countDownLatch.countDown();
                        //countDownLatch.awat();
                        //lock.notify();
                        //lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                //}
            }
    }, "t1");

使用wait/nofity的缺点是无法实现实时的通信 推荐使用countDownLatch 来实现实时的交互


使用wait/notify模拟Queue

public class MyQueue {
    
    //1 需要一个承装元素的集合 
    private LinkedList list = new LinkedList();
    
    //2 需要一个计数器
    private AtomicInteger count = new AtomicInteger(0);
    
    //3 需要制定上限和下限
    private final int minSize = 0;
    
    private final int maxSize ;
    
    //4 构造方法
    public MyQueue(int size){
        this.maxSize = size;
    }
    
    //5 初始化一个对象 用于加锁
    private final Object lock = new Object();
    
    
    //put(anObject): 把anObject加到BlockingQueue里,
//如果BlockQueue没有空间,则调用此方法的线程被阻断,
//直到BlockingQueue里面有空间再继续.
    public void put(Object obj){
        synchronized (lock) {
            while(count.get() == this.maxSize){
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //1 加入元素
            list.add(obj);
            //2 计数器累加
            count.incrementAndGet();
            //3 通知另外一个线程(唤醒)
            lock.notify();
            System.out.println("新加入的元素为:" + obj);
        }
    }
    
    
    //take: 取走BlockingQueue里排在首位的对象,
//若BlockingQueue为空,
//阻断进入等待状态直到BlockingQueue有新的数据被加入.
    public Object take(){
        Object ret = null;
        synchronized (lock) {
            while(count.get() == this.minSize){
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //1 做移除元素操作
            ret = list.removeFirst();
            //2 计数器递减
            count.decrementAndGet();
            //3 唤醒另外一个线程
            lock.notify();
        }
        return ret;
    }
    
    public int getSize(){
        return this.count.get();
    }
    
    
    public static void main(String[] args) {
        
        final MyQueue mq = new MyQueue(5);
        mq.put("a");
        mq.put("b");
        mq.put("c");
        mq.put("d");
        mq.put("e");
        
        System.out.println("当前容器的长度:" + mq.getSize());
        
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                mq.put("f");
                mq.put("g");
            }
        },"t1");
        
        t1.start();
        
        
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                Object o1 = mq.take();
                System.out.println("移除的元素为:" + o1);
                Object o2 = mq.take();
                System.out.println("移除的元素为:" + o2);
            }
        },"t2");
        
        
        try {
            //代替Thread.sleep(1000);
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        t2.start();
        
        
    }
    
    
    
} 
 

TimeUnit是java.util.concurrent包下面的一个类,TimeUnit提供了可读性更好的线程暂停操作,通常用来替换Thread.sleep()

每次写一个具有设计意义的小程序 考验的是分析能力


ThreadLocal:
ThreadLocal 是线程局部变量 是一种多线程间 并发访问变量 的解决方案
ThreadLocal 完全不提供锁,以空间换时间的方式 为每一个线程提供变量的独立副本 以保障线程安全

    private static ThreadLocal th = new ThreadLocal();

在并发量不高 的时候 ,加锁的性能会更好
座位一套无锁的线程安全解决方案 使用ThreadLocal可以减少所竞争


单例模式+多线程
在提高性能的时候 有保证了线程安全

  1. dubble check Instance
public class DubbleSingleton {

    private static DubbleSingleton ds;
    
    public  static DubbleSingleton getDs(){
        if(ds == null){
            try {
                //模拟初始化对象的准备时间...
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (DubbleSingleton.class) {
                if(ds == null){
                    ds = new DubbleSingleton();
                }
            }
        }
        return ds;
    }
}
  1. static inner class
public class Singleton {
    
    private static class InnerSingleton {
        private static Singleton single = new Singleton();
    }
    
    public static Singleton getInstance(){
        return InnerSingleton.single;
    }
    
}

你可能感兴趣的:(java,volatile)