Java线程并发与安全性问题详解

并发与线程安全问题详解

  • 什么是并发
  • 线程并发安全问题

什么是并发

想要解决线程并发安全问题,那首先要弄清楚什么是并发?
- 线程的并发原理:
- 我们先举一个例子,在你做数学题的时候能不能同时背课文,有些同学说可以一心二用啥的,咱就说正常人好吧!你会发现一个正常人是没有办法在做数学题的同时背课文的,如果你非要同时做这个两件事情,那么结果是什么样呢?我们来模拟一下:1)写个题目,背一句课文2)先做完数学题,再背语文课文。当然了,具体怎么做要看你的心情,并没有固定的方式。但是你会发现不可能出现一种情况就是在同一时刻写数学题并且背课文,问什么呢,因为你就一个大脑!
- 就像你的大脑一样,它不能同时做两件不相关的事情。同样的,电脑的CPU也不能同时处理两个及以上的线程,如果有多个任务则多个任务是轮流占用CPU的,所有实际上多个线程并不是同时运行的,而每个线程都是走走停停的(就像你写一下题目,再看一下课文一样。当然我们说并发都是针对一个一个CPU而言的,现在的双核或四核CPU是可以同时处理多个任务的)。
- 下面我们用代码来验证线程的并发性

class Two extends Thread{
    public void run(){
        for(int i=1;i<=50;i++){
            System.out.println(i);
        }
    }
}
public class TestThread{
        public static void main(String[] args) {
        //创建了t1线程
        Thread t1=new Two();
        //创建t2线程
        Thread t2=new Two();
        t1.start();
        t2.start();
    }
}

多次运行上述代码你会得到线程并发性的结果。

线程并发安全问题

我们已经知道了并发,那线程安全问题是指什么?同样的我们先来举个例子。
小明和小红从锅里捞饺子,饺子数量为5,每捞一个减一,当最后只剩下一个饺子时,小明先看到了,然后下手去捞,这时小红眼疾手快给捞了起来,此时锅里还剩0个饺子,但是小明也已经下手,此时就应该还剩-1个饺子,显然是不符合逻辑的。
所以线程安全问题就是由多个线程并发访问同一个数据(临界资源)时可能会出现先后更改此数据而得到的数据不一致。
常见的临界资源:
- 多线程共享实例变量
- 多线程共享静态公共变量
下面我们用代码来做个测试

public class DemoSyn {
    static Integer num=10;
    public static void main(String[] args) {
        final DemoSyn syn=new DemoSyn();
        Thread t1=new Thread(){
            public void run(){
                syn.printNum(0);
            }
        };
        Thread t2=new Thread(){
            public void run(){
                syn.printNum(1);
            }
        };
        t1.start();
        t2.start();
    }
    public  void printNum(int i){
            if(i==0){
                num=100;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }else{
                num=200;
            }
            System.out.println(num);
    }
}

上述代码我们预期应该是会出现100,200或者200,100,但是运行你会发现出现结果大部分是100,100和200,200。这就是因为线程的不安全导致的。
下面我们分析以下原因:当线程t1先执行时,更改num值为100,然后此线程阻塞,线程t2占用CPU,更改num值为200然后输出,1000毫秒之后t1线程继续执行,但是此时num的值已经被t2线程更改。所以结果是200,200(其他答案也可按照此过程推出)。

关于如何解决线程安全问题,可以看下一章同步异步,线程安全问题,对象锁与类锁,静态与非静态同步方法

你可能感兴趣的:(JavaSE学习笔记)