Java多线程的补充

多线程的使用场景

我之前说了很多多线程具体的知识,但是我思考了一个问题,那就是什么时候才需要用到多线程呢,初学者往往会因为钻进多线程知识的“海洋”里,因为多线程要掌握的确实有点多,而且概念都是很抽象的。

我在这里定义一个概念,使用场景如果满足了两个条件就需要使用多线程,第一,全局变量,第二,需要对全局变量进行写操作。这个时候就需要使用到多线程。例如下面,无论有多少个线程调用update这个方法都不会产生线程安全问题。因为方法的变量都是存在JVM里的方法区里面,而方法区是线程私有的。

public int update(int a) {
        int a = a + 10;
        Person p = new Person();
        a + p.count;
    }

但是,如果像下面这种情况,则会有线程安全问题

public class CPTest {
    int count = 0;

    public int update(int a) {
        return count + = a;
    }
}

因为这里的count的值很有可能在用之前就被另外的线程改了。因为这里的count+=a并不是一个原子操作。即使是一个简单的count=10在JVM中都是分为以下几步完成的。

  1. 从全局内存加载到自己的栈区空间, 作为本地缓存
  2. 对这个本地缓存进行赋值操作。
  3. 将本地缓存回写到全局内存区。

任何一个步骤被打断了都会造成错误, 线程A 刚从全局内存加载count 到本地缓存, 并将本地缓存赋值为8 , 但是还没来得及
写回去。不料线程B抢先将全局内存区改成2 。这个时候线程A中的count的值就是错误的,线程安全问题就来了。

 

在处理多线程问题中,无外乎是要解决三个问题,互斥,同步,异步这三个问题,下面我围绕这三个问题再结合我之前写的博客重点讲一下

互斥场景

这个场景主要是针对临界代码,在执行比如写操作时,只允许一个线程对其进行执行,其他线程必须在外等待,实现方法可以用我们之前说过的加锁的方法,如使用synchronized关键字,读写锁等。

同步场景

让其他线程执行完成后,需要依赖于线程返回的结果。这里的线程可以是一个,也可以是多个。如果是多个的话可以用我之前说的信号量同步来解决。一个线程的话可以用taskfuture来返回子线程返回回来的值。同步场景其实就是我之前说的线程之间的通信。

异步场景

最常见的就是我们在JS中的AJAX的异步调用方法。调用了异步方法后,主线程继续往下执行。针对这样子的AJAX异步调用,初学者往往会经常犯一个错误。在一个JS方法中先后调用两个异步调用方法,并且后一个方法中还会有变量依赖于前一个的返回值。寄希望于他们会顺序执行,先执行一个方法,后执行下一个异步方法。事实上不会,当调用第一个AJAX方法后立即会调用第二个方法。因为是异步的,所以第二个AJAX方法中依赖于第一个方法的变量会得到错误的结果。所以第二个方法应该放在第一个AJAX的回调方法里,或者将第一个异步调用方法改成同步方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值