资讯专栏INFORMATION COLUMN

并发编程基础知识二

CKJOKER / 2884人阅读

摘要:进入方法线程停止关键字虽然拥有多个线程之间的可见性,但是却不具备原子性关键字用于针对多个线程可变的变量操作,但是不能替代关键字的同步功能。

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可以实现线程之间的通信

wait/notify必须配合synchronized 关键字使用

wait释放锁 notify不释放锁

所有的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可以减少所竞争

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

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

static inner class

public class Singleton {
    
    private static class InnerSingleton {
        private static Singleton single = new Singleton();
    }
    
    public static Singleton getInstance(){
        return InnerSingleton.single;
    }
    
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70388.html

相关文章

  • Java多线程学习(七)并发编程中一些问题

    摘要:相比与其他操作系统包括其他类系统有很多的优点,其中有一项就是,其上下文切换和模式切换的时间消耗非常少。因为多线程竞争锁时会引起上下文切换。减少线程的使用。很多编程语言中都有协程。所以如何避免死锁的产生,在我们使用并发编程时至关重要。 系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)syn...

    dingding199389 评论0 收藏0
  • 我的阿里之路+Java面经考点

    摘要:我的是忙碌的一年,从年初备战实习春招,年三十都在死磕源码,三月份经历了阿里五次面试,四月顺利收到实习。因为我心理很清楚,我的目标是阿里。所以在收到阿里之后的那晚,我重新规划了接下来的学习计划,将我的短期目标更新成拿下阿里转正。 我的2017是忙碌的一年,从年初备战实习春招,年三十都在死磕JDK源码,三月份经历了阿里五次面试,四月顺利收到实习offer。然后五月怀着忐忑的心情开始了蚂蚁金...

    姘搁『 评论0 收藏0
  • Java多线程学习(七)并发编程中一些问题

    摘要:因为多线程竞争锁时会引起上下文切换。减少线程的使用。举个例子如果说服务器的带宽只有,某个资源的下载速度是,系统启动个线程下载该资源并不会导致下载速度编程,所以在并发编程时,需要考虑这些资源的限制。 最近私下做一项目,一bug几日未解决,总惶恐。一日顿悟,bug不可怕,怕的是项目不存在bug,与其惧怕,何不与其刚正面。 系列文章传送门: Java多线程学习(一)Java多线程入门 Jav...

    yimo 评论0 收藏0
  • 史上最全的并发编程学习

    一:线程基础知识 1.并发编程的基本概念 2. 线程的基本操作 3.线程之间的通信wait和notify 4.join和yield以及sleep详解 5. synchronized关键字讲解 6. volatile原理 7. 线程组 8.线程优先级 9.守护线程 10.ThreadLocal 二:JDK并发包 1.jdk并发工具类 重入锁 信号量 读写锁 CountDownLatch cyclic...

    qylost 评论0 收藏0
  • Python基础之使用期物处理并发

    摘要:本文重点掌握异步编程的相关概念了解期物的概念意义和使用方法了解中的阻塞型函数释放的特点。一异步编程相关概念阻塞程序未得到所需计算资源时被挂起的状态。 导语:本文章记录了本人在学习Python基础之控制流程篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流。 本文重点: 1、掌握异步编程的相关概念;2、了解期物future的概念、意义和使用方法;3、了解Python...

    asoren 评论0 收藏0

发表评论

0条评论

CKJOKER

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<