美文网首页
一:多线程之线程安全

一:多线程之线程安全

作者: 一森 | 来源:发表于2019-05-27 22:54 被阅读0次

    众所周知进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中肯定包含一个线程(main线程),一个进程中并且可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。

    那么什么是线程安全问题?

    当N个线程同时操作同一个全局变量或静态变量,做写的操作(修改变量值)时,可能会发生数据冲突问题(资源抢占),也就是线程安全问题。但是做读操作时不会发生数据冲突问题。

    举个雷子:

    · 创建一个打印方法(打印 当前进程名称&当前耗时任务)

    
    public static void printNum() {
        for (int i =0; i <5; i++) {
            System.out.println("线程名称:" + Thread.currentThread().getName() +" 耗时打印:" + i);
        }
    }
    
    

    ·创建两个线程

    public static class MyThread1 extends Thread {
            @Override
            public void run() {
                super.run();
    
                printNum();
            }
    }
    
    public static class MyThread2 extends Thread {
            @Override
            public void run() {
                super.run();
    
                printNum();
            }
    }
    

    ·在main函数中开启两个线程

    public static void main(String[] agrs) {
            MyThread1 myThread1 = new MyThread1();
            myThread1.start();
    
            MyThread2 myThread2 = new MyThread2();
            myThread2.start();
    }
    

    ·看下输出

    线程名称:Thread-0 耗时打印:0
    线程名称:Thread-0 耗时打印:1
    线程名称:Thread-0 耗时打印:2
    线程名称:Thread-1 耗时打印:0
    线程名称:Thread-0 耗时打印:3
    线程名称:Thread-1 耗时打印:1
    线程名称:Thread-0 耗时打印:4
    线程名称:Thread-1 耗时打印:2
    线程名称:Thread-1 耗时打印:3
    线程名称:Thread-1 耗时打印:4
    

    哎呀我去~交叉打印,我们来看下是为啥子:
    原来线程的执行是CPU随机执行的,比如我们开启N个线程,这N个线程并不是同时执行的,而是CPU快速的在这N个线程之间切换执行,所以才会出现上面的情况,那么我们如何来解决这个问题呢?

    在JDK1.5之前是通过关键字 synchronized 来进行代码同步的,也就是说当线程A执行该方法时就宣布了现在这个代码是我的了,如果 此时线程B想来执行这段代码,线程A说没门,让我干完再说;

    ·将printNum方法增加synchronized关键字

    public static synchronized void printNum() {
            for (int i = 0; i < 5; i++) {
                System.out.println("线程名称:" + Thread.currentThread().getName() + " 耗时打印:" + i);
            }
    }
    

    ·看效果

    线程名称:Thread-0 耗时打印:0
    线程名称:Thread-0 耗时打印:1
    线程名称:Thread-0 耗时打印:2
    线程名称:Thread-0 耗时打印:3
    线程名称:Thread-0 耗时打印:4
    线程名称:Thread-1 耗时打印:0
    线程名称:Thread-1 耗时打印:1
    线程名称:Thread-1 耗时打印:2
    线程名称:Thread-1 耗时打印:3
    线程名称:Thread-1 耗时打印:4
    

    在JDK1.5之后java加了个Lock锁,也是解决这个问题的,如果说synchronized是隐式的,那么Lock就是显示的,需要开发者进行上锁及解锁操作

    看骚操作:

    static Lock lock = new ReentrantLock();
    
    public static void printNum() {
            lock.lock();
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.println("线程名称:" + Thread.currentThread().getName() + " 耗时打印:" + i);
                }
            } finally {
                lock.unlock();
            }
    }
    

    首先通过ReentrantLock创建了一个Lock,在代码前加上Lock.lock方法,那么unlock要放在finally中呢,原因是假如线程A执行代码出现异常unlock可能就不能被执行,也就是无法进行解锁,那么线程B就无法拿到锁,就无法进行代码执行了

    看效果:

    线程名称:Thread-0 耗时打印:0
    线程名称:Thread-0 耗时打印:1
    线程名称:Thread-0 耗时打印:2
    线程名称:Thread-0 耗时打印:3
    线程名称:Thread-0 耗时打印:4
    线程名称:Thread-1 耗时打印:0
    线程名称:Thread-1 耗时打印:1
    线程名称:Thread-1 耗时打印:2
    线程名称:Thread-1 耗时打印:3
    线程名称:Thread-1 耗时打印:4
    

    两种线程同步(抢占资源)的解决方式:

    1、方法或代码块增加synchronized 关键字
    2、方法前lock 方法后 unlock

    相关文章

      网友评论

          本文标题:一:多线程之线程安全

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