JAVA 线程安全与同步机制

一、模拟线程不安全场景。

public class MyRunnable implements Runnable {
    private int a = 100; //共享的数据

    @Override
    public void run() {
        while (true) {
            if (a > 0) {
                //多个MyRunnable线程同时访问共享数据,结果不是想要的。导致线程不安全
                System.out.println(a);
                a--;
            } else {
                break;
            }
        }
    }
}
public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        new Thread(myRunnable).start();
        new Thread(myRunnable).start();
        new Thread(myRunnable).start();
    }

二、使用对象监视器解决问题,使其安全。将线程类修改如下。

public class MyRunnable implements Runnable {
    private int a = 100; //共享的数据

    Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            //使用了一个锁对象。这种锁又叫:同步锁,对象锁,对象监视器。
            synchronized (obj) {
                if (a > 0) {
                    System.out.println(a);
                    a--;
                } else {
                    break;
                }
            }
        }
    }
}

对象锁

  优点:保证了线程安全,同一时间只能有一个线程执行共享数据。

  缺点:程序频繁的判断锁、获取锁和释放锁,程序的效率会降低。

三、使用同步方法解决问题,其实思想和上面解决方法一直。将线程类修改如下。

public class MyRunnable implements Runnable {
    private int a = 100; //共享的数据

    Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            boolean bo = inA();
            if (!bo) break;
        }
    }

    //使用的也是对象锁,锁对象就是this
    public synchronized boolean inA(){
        if (a > 0) {
            System.out.println(a);
            a--;
            return true;
        } else {
            return false;
        }
    }

}

三、使用静态同步方法解决问题,与同步方法的区别是锁对象不同。将线程类修改如下。

public class MyRunnable implements Runnable {
    private static int a = 100; //共享的数据

    Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            boolean bo = inA();
            if (!bo) break;
        }
    }

    //使用的也是对象锁,锁对象就是奔本类的class属性->class文件对象(反射机制)。MyRunnable.class
    public static synchronized boolean inA(){
        if (a > 0) {
            System.out.println(a);
            a--;
            return true;
        } else {
            return false;
        }
    }

}

 使用Lock锁解决线程安全问题,将线程类修改如下。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyRunnable implements Runnable {
    private static int a = 100; //共享的数据

    /*
    1、创建ReentrantLock对象。
    2、在可能出现线程安全问题代码【前】调用【lock()】方法获取锁
    3、在可能出现线程安全问题代码【后】调用【unlock()】方法释放锁
     */
    Lock lock = new ReentrantLock();

    // @Override
    public void run() {
        while (true) {
            lock.lock();
            try {
                if (a > 0) {
                    System.out.println(a);
                    a--;
                } else {
                    break;
                }
            } catch (Exception e) {
            } finally { //无论是否异常,都需要是否锁
                lock.unlock();
            }
        }
    }
}

 

posted @ 2021-09-02 15:52  饮木  阅读(48)  评论(0编辑  收藏  举报