java线程安全

java线程安全,第1张

java线程安全 java线程安全
  • 方法内的变量线程安全(方法内部变量具有私有性)
  • 实例变量(类下的直接定义的变量)非线程安全(可通过对 *** 作方法加锁解决)
class MyEntity6 {
    private int num = 10;
    // 加锁解决线程不安全问题
    synchronized public void add(int addNum) {
        this.num += addNum;
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("num = " + num);
    }
}

public class StudyThreads6线程安全 {
    public static void main(String[] args) {
        MyEntity6 myEntity6 = new MyEntity6();

        Thread t1 = new Thread() {
            @Override
            public void run() {
                myEntity6.add(100);
            }
        };

        Thread t2 = new Thread() {
            @Override
            public void run() {
                myEntity6.add(100);
            }
        };

        t1.start();
        t2.start();
    }
}
资源不共享时候无需加锁

当资源不共享时候,各线程有自己的相应的变量,不加锁多线程之间也不会相互影响。

脏读(写加锁可以解决变量交叉造成的不安全的问题,读变量时候也可能造成不安全)
  • 脏读即在读的时候此时的变量已经被其他线程更改了
  • 可以通过在读方法上加锁来解决(即在读和写方法上都加锁)
  • synchronize锁的是对象,当共享实例变量时候传入的是同一个对象,synchronize会对这个对象加锁。
synchronize 锁重入
  • 在被锁的方法中调用本类中其他加锁的方法时候,锁会自动重入进来
  • 锁重入支持在父子继承
  • 如果不能锁重入则会造成死锁(当前方法持有锁,方法内部调用的方法请求锁)

当出现异常时候锁会自动释放

同步不能继承

父类方法已经同步之后,子类方法需要重写加入synchronize关键字才能实现同步功能,否则不是同步方法。

synchronize(对象),针对对象加锁,如果对象不一样则相应的方法或代码块可以异步执行
  1. synchronize针对对象加锁,传入对象不一样则锁互不影响
  2. synchronize(this) {}对当前对象加锁
synchronize修饰静态方法与synchronize(x.class)
  1. synchronize修饰静态方法时,是对拥有方法的class上锁;而synchronize关键字加到非static方法上时,是给对象上锁。(代码如下)
  2. 对class上锁对所有实例都起作用
  3. synchronize(x.class) 与synchronize static作用一样,都是给对象上锁

printA() printB() 方法是对class加锁,printC()是给对象上锁。锁对象不一样 C与AB不同步:

// synchronize修饰静态方法加锁是对class上锁
// synchronize修饰非静态方法是对对象上锁
// 验证上锁不同如下

class Service {
    public synchronized static void printA() {
        try {
            System.out.println("线程名字:" + Thread.currentThread().getName() + "在 " + System.currentTimeMillis() +
                    " 进入A方法。");
            Thread.sleep(3000);
            System.out.println("线程名字:" + Thread.currentThread().getName() + "在 " + System.currentTimeMillis() +
                    " 离开A方法。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized static void printB() {
        try {
            System.out.println("线程名字:" + Thread.currentThread().getName() + "在 " + System.currentTimeMillis() +
                    " 进入B方法。");
            Thread.sleep(3000);
            System.out.println("线程名字:" + Thread.currentThread().getName() + "在 " + System.currentTimeMillis() +
                    " 离开B方法。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void printC() {
        try {
            System.out.println("线程名字:" + Thread.currentThread().getName() + "在 " + System.currentTimeMillis() +
                    " 进入C方法。");
            Thread.sleep(3000);
            System.out.println("线程名字:" + Thread.currentThread().getName() + "在 " + System.currentTimeMillis() +
                    " 离开C方法。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


public class StudyThreads7synchronize给静态方法加锁 {
    public static void main(String[] args) {
        Service myService = new Service();
        Thread threadA = new Thread(() -> myService.printA());
        Thread threadB = new Thread() {
            @Override
            public void run() {
                myService.printB();
            }
        };
        Thread threadC = new Thread() {
            @Override
            public void run() {
                myService.printC();
            }
        };

        threadA.setName("A");
        threadB.setName("B");
        threadC.setName("C");
        threadA.start();
        threadB.start();
        threadC.start();

    }
}

输出结果:

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/4670984.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-06
下一篇 2022-11-06

发表评论

登录后才能评论

评论列表(0条)

保存