Java多线程安全问题

什么情况下会产生线程安全问题?

同时满足以下两个条件时:

  • 多个线程在操作共享的数据
  • 操作共享数据的线程代码有多条
    共享数据存在被并发修改的可能,就会导致线程安全问题的产生。

线程安全问题解决思路

将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程不可以参与运算。
当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
使用Java中同步代码块可以解决这个问题。

synchronized(对象) {
需要被同步的代码;}

这个对象一般称为同步锁。
同步的前提:同步中必须有多 个线程并使用同一个锁。
同步的好处:解决了线程的安全问题。
同步的弊端:相对降低了效率,因为同步外的线程的都会判断同步锁。

Thread thread1 = new Thread() {
            @Override
            public void run() {
                while(true) {
                    synchronized (Class.class) {
                        if(ticket>0) {
                            ticket--;
                        } else {
                            break;
                        }
                    }
                }
            }
        };
Thread thread2 = new Thread() {
            @Override
            public void run() {
                while(true) {
                    synchronized (Class.class) {
                        if(ticket>0) {
                            ticket--;
                        } else {
                            break;
                        }
                    }
                }
            }
        };
thread1.start();
thread2.start();

注意事项:使用同一把锁的代码才能实现同步;没有获取到锁的线程即使得到了cpu的执行权,也不能运行;尽量减少锁的范围,避免效率低下;锁可以加在任意类的代码中或方法上。

死锁

使用同步的多个线程同时持有对方运行时所需要的资源
多线程同步时,多个同步代码块嵌套,很容易出现死锁
锁的嵌套越多,越容易造成死锁的情况
死锁的情况

private static String s1 = "筷子左";
private static String s2 = "筷子右";

public static void main(String[] args) {
    new Thread() {
        public void run() {
            while(true) {
                synchronized(s1) {
                    System.out.println(getName() + "...拿到" + s1 + "等待" + s2);
                    synchronized(s2) {
                        System.out.println(getName() + "...拿到" + s2 + "开吃");
                    }
                }
            }
        }
    }.start();
    
    new Thread() {
        public void run() {
            while(true) {
                synchronized(s2) {
                    System.out.println(getName() + "...拿到" + s2 + "等待" + s1);
                    synchronized(s1) {
                        System.out.println(getName() + "...拿到" + s1 + "开吃");
                    }
                }
            }
        }
    }.start();
}
image

你可能感兴趣的:(Java多线程安全问题)