如果有人问你什么是多线程,你这样说,面试管肯定对你另眼相看!

什么是线程安全?我相信不少做了几年开发的人,面试都会遇到这个问题.

不理解的人一般会说,线程安全就是指,线程的安全啊,这回答了等于没说!

线程安全其实指的是内存的安全,为什么这么说呢?这还是和操作系统有关系!

操作系统一般都是多任务的,就是多个进程同时进行(准确来说是cpu切换的速度太快了),所以每个进程之间访问的数据要保证安全,所以每个进程都只能访问自己的内存,不能访问别的进程,这个操作系统已经处理过了.

但是每个进程除了自己私有的一个内存空间外,还有一个公共的区域,"堆"内存;进程中的所有线程都可以访问该区域,这也就会造成一定的安全隐患.

这就相当于你把你最新款的水果手机放到了二七广场上,一天后,你又过去拿手机,发现没了~不要感到意外和惊讶,因为你把手机(数据)放到了广场("堆"内存),而路人就相当于每个进程,去访问了手机(数据),所以你发现手机没了,你甚至都不知道谁拿走了~

那你说这个问题可以解决吗?

答案是肯定的!你手机拿在手里不就好了,干嘛放在广场呢!

1私有化

实际上,没有人会把手机放到广场上的,因为手机是你的私人物品.

程序中也是如此,操作系统会为每个程序分配一个空间,叫做"栈"内存,其他线程无权访问,这个是操作系统处理过的.

如果数据被放到栈内存中,就可以保证其他线程不能访问,进而达到线程安全问题,程序中常见的作法就是:局部变量

public int sum(int[] numbers){
		int count=0;
		for (int num : numbers) {
			count += num;
		}
		return count;
	}

上面实例中的count 就属于局部变量.它就会被分配到栈内存空间中.

每个线程访问进来,都为为每个线程分配自己的内存空间,所以就能保证线程安全;

2常量化

手机放到公共区域,个人肯定不会这么干!

但是,有一个地方会,就是线下体验店,比如小米线下体验店吧,里面放的有所有的小米最新出的产品,你可以进去随便玩,但是就是不能带走,因为每个产品都有一个警报先,你敢拿下来,就响......(付钱的可以拿走哦)

在程序中,就是加一个final最终的,就是线程可以使用,但是不能修改!

 public static final String DATE_FORMAT = "yyyy-MM-dd";

3加锁

一种情景就是,你去超时购物,把电动车放到超时门口,然后你会怎么做呢?

对,就是加一把锁,然后你购物回来,你的车就还在那里.超市门口属于你的私有空间吗?肯定不属于了,但为什么可以存放你的私人物品呢?原因很简单,就是锁.

程序也是一样.如果公共区域(堆内存)的数据,要被多个线程操作时,为了确保数据的安全(或一致)性,需要在数据旁边放一把锁,要想操作数据,先获取锁再说吧。

假设一个线程来到数据跟前一看,发现锁是空闲的,没有人持有。于是它就拿到了这把锁,然后开始操作数据,干了一会活,累了,就去休息了。

这时,又来了一个线程,发现锁被别人持有着,按照规定,它不能操作数据,因为它无法得到这把锁。当然,它可以选择等待,或放弃,转而去干别的。

第一个线程之所以敢大胆的去睡觉,就是因为它手里拿着锁呢,其它线程是不可能操作数据的。当它回来后继续把数据操作完,就可以把锁给释放了。锁再次回到空闲状态,其它线程就可以来抢这把锁了。还是谁先抢到锁谁操作数据。


class ClassAssistant {

    double totalScore = 100;
    final Lock lock = new Lock();

    void addScore(double score) {
        lock.obtain();
        totalScore += score;
        lock.release();
    }

    void subScore(double score) {
        lock.obtain();
        totalScore -= score;
        lock.release();
    }
}

 

假定一个班级的初始分数是100分,这个班级抽出10名学生来同时参加10个不同的答题节目,每个学生答对一次为班级加上5分,1答错一次减去5分。因为10个学生一起进行,所以这一定是一个并发情形。

因此加分和减分这两个方法被并发的调用,它们共同操作总分数。为了保证数据的一致性,需要在每次操作前先获取锁,操作完成后再释放锁。

4ThreadLocal类

生活场景:比如公司发放中秋礼品,每个人发一个666g重的纯金月饼.比如公司100个人,如果老板说,大家自己抢吧,抢到多少都是你的,那么肯定会发生一件事,有的人抢了多个,有的人没抢到.

但是如果礼品是每个人都去财务室领取,然后领取完毕签字呢?肯定就不会出问题了吧.

在程序上就是:

要让公共区域堆内存中的数据对于每个线程都是安全的,那就每个线程都拷贝它一份,每个线程只处理自己的这一份拷贝而不去影响别的线程的,这不就安全了嘛。没错,就是用ThreadLocal类。

class Student {

        ThreadLocal total = new ThreadLocal<>();

        String jieguo() {
            double score = total.get();
            if (score >= 60) {
                return "通过";
            }
            return "不通过";
        }

    }

比如张三90分,运行就是通过:李四59分,运行就是不通过;肯定不会出现张三90分,结果是不通过;

 

总结:

  1. 私有化,把你的东西放在自己的私有空间,就能保证安全---位置隔离;
  2. 常量,体验店,你可以体验,但不能拿走----数据隔离;
  3. 加线程锁,可以把电车停到超市门口,但是要上锁----锁标记;
  4. 用ThreadLocal类,复制多份

我写了这么多,当然也是有私心的,只求一个关注而已.

如果有人问你什么是多线程,你这样说,面试管肯定对你另眼相看!_第1张图片

关注后回复(0728可以领取大厂面试题)

 

 

 

你可能感兴趣的:(Java)