JAVA基础-线程安全(续)

线程安全主要涉及竞态条件、临界区和死锁等问题。为确保线程安全,可以使用同步机制、不可变对象、线程局部存储或避免共享数据。volatile关键字能保证可见性但不保证原子性,因此仍可能出现线程安全问题。示例代码展示了如何使用wait()和notifyAll()避免双循环锁的死锁问题。
摘要由CSDN通过智能技术生成
  1. 什么是线程安全?

多个线程同时操作(读写 写写 )共享资源时,导致共享资源被线程不确定的修改读取

  1. 线程安全问题会导致什么样的结果?

  • 竞态条件(Race condition):多个线程同时修改同一个变量或数据结构,导致结果与预期不符。

  • 临界区(Critical section):多个线程同时访问同一个共享资源,导致数据不一致或程序崩溃。

  • 死锁(Deadlock):多个线程互相等待对方释放锁,导致程序无法继续执行。

  1. 为了保证线程安全,可以采取哪些操作?

  • 使用同步机制(Synchronization):例如互斥锁、条件变量、信号量等,可以保证多个线程对共享数据的访问和修改是互斥的。

  • 使用不可变对象(Immutable object):即创建一个对象后,其状态不可改变。由于不可变对象的状态不会发生变化,所以多个线程同时访问该对象时不会出现竞态条件。

  • 使用线程局部存储(Thread-local storage):即为每个线程分配独立的存储空间,从而避免多个线程之间的数据冲突和同步问题。

  • 避免共享数据:即尽可能避免多个线程之间对同一个共享数据的访问,而是将共享数据拆分为多个独立的部分,每个部分只由一个线程访问和修改。

  1. Volatile能否保证线程安全?

public class Manage{

    static volatile boolean flag1 = true;

        new Thread (() -> {
            System.out.println ("ThreadA - start" + flag1);
            while(flag1){
//                System.out.print ("");
            }
            System.out.println ("ThreadA - stop" + flag1);
        }).start ();

        try {
            Thread.sleep (2000);
        } catch (InterruptedException e) {
            throw new RuntimeException (e);
        }

        new Thread (() -> {
            System.out.println ("ThreadB start");
            flag1 = false;
            System.out.println ("ThreadB stop -- " + flag1);
        }).start ();

以上程序运行后,当线程A启动后,线程B启动并将flag1赋值为false,如果不加volatile修饰flag1,线程A中的flag1仍然是true,volatile的作用是保持flag1的可见性,但volatile不能保证线程安全。

可见性是指一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果。另一个线程马上就能看到。比如:用volatile修饰的变量,就会具有可见性。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存。所以对其他线程是可见的。但是这里需要注意一个问题,volatile只能让被他修饰内容具有可见性,但不能保证它具有原子性。比如 volatile int a = 0;之后有一个操作 a++;这个变量a具有可见性,但是a++ 依然是一个非原子操作,也就是这个操作同样存在线程安全问题。

      new Thread (){
            @Override
            public void run(){
                synchronized (objA) {
                    System.out.println ("持有A锁");
                    try {
                        Thread.sleep (2000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException (e);
                    }
                    synchronized (objB) {
                        objB.notifyAll ();
                        System.out.println ("执行");
                    }

                }
                System.out.println ("解锁");
            }
        }.start ();

        new Thread (){
            @Override
            public void run(){
                try {
                    Thread.sleep (1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException (e);
                }
                try {
                    System.out.println ("持有B锁");
                    synchronized (objB) {
                        objB.wait ();// 释放锁
                        synchronized (objA) {
                            System.out.println ("2执行");
                        }
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException (e);
                } finally {
                    System.out.println ("objB wait....");
                    synchronized (objB) {

                        synchronized (objA) {
                            System.out.println ("2执行");
                        }

                    }

                }
                System.out.println ("2解锁");
            }
        }.start ();
    }

    static Object objA = new Object ();
    static Object objB = new Object ();


}

双循环锁很容易出现死锁问题,此时利用wait()方法和notifyAll()方法让线程2等待,释放锁,让线程1得到objB的资源,notifyAll()方法是唤醒当前对象上的等待线程;notify()是唤醒单个线程,notifyAll()是唤醒所有的线程,唤醒线程2,让线程2得以启动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值