线程安全问题解决--java多线程

10/24 14:48
阅读数 42

线程安全问题解决–java多线程

在日常工作当中,当我们用到多线程操作公共资源时免不了会遇到一些问题,比如程序执行时多个线程用时操作一个公共资源却发现结果和我们预想的不一致,那到底是为何呢?我们来做一个小例子。

例子:
比如当我们想要开启两个线程同时对公共资源数组saveWord添加数据时,发现程序执行完毕时结果每次都不一样。

package com.nxw.Thread;

import java.util.Arrays;

public class ThreadSafe {
   
   

    private static int index=0;
    public static void main(String[] args) throws InterruptedException {
   
   
        final String[] saveWord = new String[2];
        Runnable runnable1 = new Runnable() {
   
   
            public void run() {
   
   
                saveWord[index] = "hello ";
                index++;
            }
        };

        Runnable runnable2 = new Runnable() {
   
   
            public void run() {
   
   
                saveWord[index] = " world";
                index++;
            }
        };

        Thread thread1 = new Thread(runnable1,"子线程1");

        Thread thread2 = new Thread(runnable2,"子线程2");

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println(Arrays.toString(saveWord));
    }
}

以上代码多执行几次你就会发现,每次执行的结果都不一样。

执行结果:

  • [hello , null]
  • [hello , word]
  • [word, null]

那么出现这样的结果肯定不是我们想要的,而我们想要的结果要么是[hello , word]要么是[word,hello],那么为什么会出现有null这样的问题呢?

想要知道问题的原因,我们首先的搞清楚线程的概念,线程在执行时是怎么分配的。

我们的线程在执行的时候是有时间限制的,并不是一直等待你执行完毕之后下一个线程才开始执行。而是有一个时间的限制。比如说例子1中run方法执行完毕需要花费5s的时间,而操作系统规定每个线程只给你3s的时间去执行,所以当thread1刚刚把word添加到数组中的时候,thread2就开始执行了,这个时候了thread2获取的index仍然是0,所以就把thread1添加到数组中的值给覆盖掉了。给数据带来的安全问题。

那么如何在应用程序当中来保证线程的安全性呢?

保证资源安全:

要想在应用程序当中来保证线程的安全性,那么就要用到java的同步机制。

方式:使用同步代码块

package com.nxw.Thread;

import java.util.Arrays;

public class ThreadSafe {
   
   

    private static int index=0;
    public static void main(String[] args) throws InterruptedException {
   
   
        final String[] saveWord = new String[2];
        Runnable runnable1 = new Runnable() {
   
   
            public void run() {
   
   
                synchronized(saveWord){
   
   
                    saveWord[index] = "hello ";
                    index++;
                }

            }
        };

        Runnable runnable2 = new Runnable() {
   
   
            public void run() {
   
   
                synchronized (saveWord){
   
   
                    saveWord[index] = " world";
                    index++;
                }
            }
        };

        Thread thread1 = new Thread(runnable1,"子线程1");

        Thread thread2 = new Thread(runnable2,"子线程2");

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println(Arrays.toString(saveWord));
    }
}


由于我们在代码中加了thread1.join(),thread2.join(),所以这两个线程的执行是优先于main方法的主线程的。

加上synchronized代码块后对共享资源saveWord上了锁,当有线程使用这个共享资源saveWord时其他线程等待,保证了共享资源的安全性。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部