ADeveloperH Blog

Meet a better self !

Android 周边技术分享


Java使用同步解决线程安全问题的弊端及带来的问题

1 多线程使用同步解决方案引入的问题

由于多线程会引入线程安全问题,我们使用了同步或者加锁的方法来解决这个问题,但是使用同步的方法也会带来相应的弊端。

主要有如下两个弊端:

  1. 使用同步的方法效率低
  2. 如果出现同步嵌套,会出现死锁问题。

对于第一个问题,告诉我们要慎用同步,只在必要的位置添加同步方法,而不是为了安全添加不必要的同步,这样会导致效率的降低,因为如果使用了同步会有锁机制,执行相关代码前会对锁进行相应的检查,这样就会降低效率。

第二个问题是主要讲解的问题,这个我们需要在程序中尽量避免,如果出现死锁问题,会导致所有的工作都无法正常完成,陷入相互等待的状态。

2 死锁案例

通过一段代码来直观的了解死锁发生的场景。代码如下:

package com.example.thread.one;  
  
public class DieLockDemo {  
      
    public static void main(String[] args) {  
        Object lockA = new Object();  
        Object lockB = new Object();  
          
        MyThread myThread1 = new MyThread(true, lockA, lockB);  
        MyThread myThread2 = new MyThread(false, lockA, lockB);  
          
        myThread1.setName("线程1");  
        myThread2.setName("线程2");  
          
        myThread1.start();  
        myThread2.start();  
    }  
  
}  
  
class MyThread extends Thread{  
    private boolean flag;  
    private Object lockA;  
    private Object lockB;  
  
    public MyThread(boolean flag, Object lockA, Object lockB) {  
        super();  
        this.flag = flag;  
        this.lockA = lockA;  
        this.lockB = lockB;  
    }  
  
    @Override  
    public void run() {  
        super.run();  
        if(flag){  
            synchronized (lockA) {  
                System.out.println(Thread.currentThread().getName() + " :if lockA");  
                synchronized (lockB) {  
                    System.out.println(Thread.currentThread().getName() + " :if lockB");  
                }  
            }  
        }else{  
            synchronized (lockB) {  
                System.out.println(Thread.currentThread().getName() + " :else lockB");  
                synchronized (lockA) {  
                    System.out.println(Thread.currentThread().getName() + " :else lockA");  
                }  
            }  
        }  
    }  
}  

上边程序可能出现的运行结果如下:

分析出现的原因:

当线程1获取的lockA的锁后执行完System.out.println(Thread.currentThread().getName() + “ :if lockA”);语句后时间片用完,线程2获取到时间片并且进入运行状态,线程2获取到lockB的锁后执行System.out.println(Thread.currentThread().getName() + “ :else lockB”);后需要获取lockA的锁,发现线程1还没有释放lockA的锁,因此进入阻塞状态,接下来线程1进入运行状态,同样的,线程1接着执行发现需要lockB的锁,但是这个锁被线程2使用也没有释放,此时线程1也进入阻塞状态。这样就产生了所谓的死锁问题,线程1和线程2相互等待,都无法执行接下来的代码。

最近的文章

Java并发编程:Synchronized及其实现原理

1 Synchronized的基本使用在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访问对象并要求操作相同资源时,分割了原子操作就有可能出现数据的不一致或数据不完整的情况,为避免这种情况的发生,我们会采取同步机制,以确保在某一时刻,方法内只允许有一个线程。采用 synchronized 修饰符实现的同步机制叫做互斥锁机制,它所获得的锁叫做互斥锁。每个对象都有一个 monitor (锁标记),当线程拥有这个锁标记时才能访问这个资源,没有锁标记便进入锁池。任何一个对象系统都...…

继续阅读
更早的文章

Java中多线程线程的控制及常用方法

1 线程的控制方法1.1 休眠线程使用sleep()方法来使当前线程休眠,不再向下执行。该方法是Thread的静态方法:public static void sleep(long millis) throws InterruptedException millis - 以毫秒为单位的休眠时间。 public static void sleep(long millis, int nanos) throws InterruptedException millis - 以毫秒为单位的休眠时间。 ...…

继续阅读