java线程安全问题

多线程不安全,主要因为cpu分配机制,谁获得了cpu谁就能执行,因此造成了线程的不安全.

现在总结一下判断线程安不安全的方法:

1.明确哪些代码是多线程运行的代码,
2.明确共享数据
3.明确多线程运行代码中哪些语句是操作共享数据.

通过以上三点,写一段代码,

package com.niuli.develop;

public class Test {
    public static void main (String [] args) {
        Cus c = new Cus();
        new Thread(c).start();
        new Thread(c).start();
    }
}

class Bank{
    private int sum = 0;
    public void add(int n) {
        sum = sum + n;
        System.out.println("sum= "+sum);
    }
}

class Cus implements Runnable{
    Bank b = new Bank();
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            b.add(100);
        }
    }
}

很简单的例子,
首先第一步,找到多线程运行的代码

也就是run方法里面的代码
for (int i = 0; i < 3; i++) {
            b.add(100);
        }
        另外这里用到了Add方法,所以add也算
 public void add(int n) {
        sum = sum + n;
        System.out.println("sum= "+sum);
    }

第二步,找到共享数据

Bank b = new Bank();
private int sum = 0;

第三步,明确多线程使用的共享数据.
首先对于数据b就一条语句使用了这个共享变量,因此不会出现线程不安全,但是对于sum,有两条语句使用的,所以就会出现线程安全问题,

解决办法:采用同步代码块

Object obj = new Object();
    public void add(int n) {
        synchronized (obj) {
            sum = sum + n;
            System.out.println("sum= "+sum);
        }
    }

或者:同步函数

public synchronized void add(int n) {
            sum = sum + n;
            System.out.println("sum= "+sum);
    }

以上就是线程安全的解决办法,同步机制虽然游侠,但是带来了一定的性能损耗,所以,对操作共享数据的部分执行同步,尽量减少这种损耗

补充:

如果同步函数是静态的,那么使用的锁就必须是所在类的字节码文件对象,也就是 类名.class,解释来说,静态是和类一起加载的,所以在静态加载的时候是不可能有object的对象,所以锁就必须用在静态加载之前的一个对象.

有几个原则的:
程序次序规则:一个线程内,代码的执行会按照程序书写的顺序
管程锁定原则:对同一变量的unlock操作先行发生于后来的lock操作
volatile变量规则:对一个volatile的写操作先行发生于后来的读操作
线程启动原则:Thread的start()先行发生于线程内的所有动作
线程终止原则:线程内的所有动作都先行发生于线程的终止检测
线程中断原则:对线程调用interrupt()先行发生于被中断的代码检测到是否有中断发生
对象终结原则:一个对象的初始化操作先行发生于finalize()方法
传递性:A先行发生于B,B先行发生于C,那么A先行发生于C

猜你喜欢

转载自blog.csdn.net/qq_34991051/article/details/80224124