美文网首页
JAVA多线程-什么是线程安全

JAVA多线程-什么是线程安全

作者: philcoulso_b627 | 来源:发表于2019-08-05 21:22 被阅读0次
什么是线程

线程是比进程更小的运行单位,它被包含在进程之中,是进程实际的运行单位,一个线程是指进程单一的控制流,一个进程可以并发多个线程,每条线程并行执行不同的任务。(来源百度)

  • 并发:同一时间段内,多个任务都在执行(单位时间内不一定同时执行)
    -并行:单位时间内,多个任务同时执行
Java中如何创建线程

Java中创建线程的方式有三种

  • 通过implement Runable 接口
  • 通过extents Thread 类
  • 通过Callable和Future创建线程
    1.implement Runnable方式
public class threadSafe{
public void static main(String[] args){
 Thread thread=new Thread(new Runnable() { //第一种方式 直接new一个Runnable 实例
              @Override
              public void run() {
                  System.out.println("this is a thread");
              }
          });
          thread.start();
      mythread mythread=new mythread();
     Thread   thread2=new Thread(mythread);//通过创建mythread实例创建线程
}
}
class mythread implements Runnable{
  @Override
    public void run() {
        for(int i=0;i<10;i++){
            a++;
            System.out.println("running thread"+" a:"+a);
           }
    }
}

后两者有兴趣的同学可去菜鸟教程上学习,在这就不写了.
https://www.runoob.com/java/java-multithreading.html

什么是线程安全

一个类是线程安全的,是指被多个线程访问时,类可以持续进行正确的行为.
当多个线程访问一个对象时,如果我们不考虑线程在运行环境下的交替执行和调度,并且不需要额外的同步及在调用方代码不必做其它的协调,那么我们称这个类是线程安全的(来自java并发编程实战)
多线程中,程序的执行顺序我们是不知道的,比如什么时候执行这段代码


threadSafe.PNG

让我们看看实际代码中的输出

生产者

class  product implements Runnable{
    private int DEAFULT_CUSOTME_NUM=5;
    private Thread thread;
    private String ThreadName;
    private goods goods;
    /**
     * none constructor
     */
    product(){}

    /**
     *
     * @param ThreadName
     * Get threadName for this thread
     */
    product(String ThreadName,goods goods){
        this.ThreadName=ThreadName;
        this.goods=goods;
    }
    public void start(){
        if(thread==null){
            thread =new Thread(this,ThreadName);
            thread.start();
        }
    }
    @Override
    public void run() {
        SimpleDateFormat formatter=new SimpleDateFormat("yyyy/MM/dd hh:mm:ss:SSS");
            for(int i=0;i<5;i++){
                    System.out.println("thread name :" + thread.getName() + "consume goods:"
                            + DEAFULT_CUSOTME_NUM + "remain goods:" +
                            goods.consumeGoods(DEAFULT_CUSOTME_NUM) + "   current time"
                            + formatter.format(new Date()) + "\n i:" + i);
                    ; //default product five goods;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

    }
}

消费者

class  custome implements Runnable{
    private int DEAFULT_CUSOTME_NUM=5;  //default good num
    private Thread thread;
    private String ThreadName;
    private goods goods;

    /**
     * none constructor
     */
    custome(){}

    /**
     *
     * @param ThreadName
     * Get threadName for this thread
     */
    custome(String ThreadName,goods goods){
        this.ThreadName=ThreadName;
        this.goods=goods;
    }
    public void start(){
        if(thread==null){
            thread =new Thread(this,ThreadName);
        thread.start();
        }
        }
@Override
public void run() {
        SimpleDateFormat formatter=new SimpleDateFormat("yyyy/MM/dd hh:mm:ss:SSS");
        for(int i=0;i<5;i++){
        System.out.println("thread name :"+thread.getName()
        +"  product goods:"+DEAFULT_CUSOTME_NUM+"remain goods:"+
        goods.addGoods(DEAFULT_CUSOTME_NUM)+" current time"
        +formatter.format(new Date())+"\n i:"+i);  //default product five goods
 
        }
        }

main方法

public class threadSafe {
    static int DEFAULT_GOODS_NUM=0;
    public static void main(String[] args) {
         goods goods=new goods(DEFAULT_GOODS_NUM);
         custome custome2=new custome("product ",goods);
         product product1=new product("consume ",goods);
        custome custome1=new custome("product 1",goods);
        product product2=new product("consume 2",goods);
         custome2.start();
         product1.start();
         custome1.start();
         product2.start();
     }
}

我们来观察一下输出


threadSafeprint.PNG

由于我加了threadSleep,所以会按从0-5的顺序执行
虽然i:0的时候,输出顺序是0->10->5->5,结果是没有错误的,因为我们无法控制线程什么时候开始输出,比如执行操作的时候,线程一起执行,实际上读入变量顺序是这样的,produc->consumer 2-> consume->product 1
但是执行 i:1的时候,出现了问题,product 和product 1同时输出了5。说明这两个线程发生了像上面一样的图的情况,在product和product 1 执行前,先执行了consume方法,此时变量为0,当product和product1执行时,同时读入变量值0,执行addgood方法,得到了一样的结果。
这就出现了线程不安全的情况

如果将它变为线程安全

1.将goodnum设置为volatile.
为什么设置volatile有效呢,volatile的作用到底是什么
在当前java内存模型下,线程可以把变量保存到本地内存,而不是在主存中进行读写,这就可能造成一个线程在主存中修改了变量的值,而另一个线程还在使用它在寄存器中变量值的拷贝,造成数据的不一致


2.PNG

使用volatile声明变量,目的是告诉jvm,这个变量是不稳定的,每次使用它都应该去主存中读写


3.PNG
volatilel 声明的变量除了保证可见性,还能防止指令重排
2.在修改goodnum的方法中加入 synchronized
synchronized可以保证修饰的代码中,任何时刻只能有一个线程执行。
class goods {
    private  volatile int num;

    /**
     * none constructor
     */
    goods(){

    }
    /**
     *
     */
    goods(int num){
        this.num=num;
    }
    public void setNum(int num){
        this.num=num;
    }
    public synchronized  int getNum(){  //该代码块为同步代码块
        return this.num;
    }
    public  synchronized int addGoods(int num){
      return   this.num+=num;
    }

    public  int consumeGoods(int num){
        return  this.num-=num;
    }
}

相关文章

  • 后端架构师技术图谱(三)-并发、锁、设计模式(二)

    并发 多线程 《40个Java多线程问题总结》 线程安全 《Java并发编程——线程安全及解决机制简介》 一致性、...

  • ThreadLocal实现原理揭秘

    ThreadLocal是什么?对java多线程有了解的人都清楚,在多个线程程序中,会出现线程安全性问题,即多线程是...

  • ConcurrentHashMap

    总结 HashMap在多线程中不安全,java提供了线程安全的ConcurrentHashMap 类,保证在多线程...

  • 多线程juc锁

    java_basic 1 线程安全 在Java多线程编程当中,实现线程安全: 内部锁(Synchronized...

  • 带你搞懂Java多线程(四)

    带你搞懂Java多线程(一)带你搞懂Java多线程(二)带你搞懂Java多线程(三) 什么是线程间的协作 线程之间...

  • Notes: Java下的线程安全容器小小整理

    Java下的线程安全容器 在编写多线程的Java程序时,难免会使用到各种各样的容器。Java本身提供了许多线程安全...

  • JAVA开发-常见面试题

    一、java多线程 线程池的原理,为什么要创建线程池? 线程的生命周期,什么时候会出现僵死进程? 什么是线程安全,...

  • Java多线程(二十四)---ConcurrentHashMap

    移步java多线程系列文章ConcurrentHashMap是线程安全且高效的HashMap。 1 为什么要使用C...

  • kotlin 单利模式

    1. 懒汉式 java线程不安全 缺点是在多线程不能正常工作 线程安全 效率比较低 kotlin线程不安全 线程...

  • java_多线程

    java_多线程 线程创建方式;join用法; sleep和wait区别; 线程安全和不安全的java集合; St...

网友评论

      本文标题:JAVA多线程-什么是线程安全

      本文链接:https://www.haomeiwen.com/subject/jmdsdctx.html