Java多线程编程——对象及变量的并发访问 02

来源:互联网 发布:红杉网络 编辑:程序博客网 时间:2024/05/16 15:06

Java多线程编程——对象及变量的并发访问 02

synchronized同步方法

  • 方法内的变量为线程安全:运行时,入栈操作,故为线程安全
  • 实例(对象)变量非线程安全:运行时,在堆中,故为非线程安全
  • 关键字synchronized取得的锁都是对象锁
  • synchronized锁重入:当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁的。
  • 异常时,自动释放锁
  • 同步不能继承
  • synchronized(this):同步代码块,将代码块用synchronized(this){}包起来,可以减少同步的区域
  • synchronized(非this对象):好处在于不和其他同步块抢this锁
  • 静态同步synchronized方法:对当前的Class类进行持锁。
  • synchronized(class)代码块
  • String常量池。
  • 锁对象的属性的改变不影响同步

查找死锁

进入JDK的bin目录,执行jps命令可以得到运行的线程Run的id值,然后执行jstack命令jstack -l id值,就可以看见是否有死锁

volatile

作用

  • 主要作用是使变量在多个线程间可见
  • 强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值

示例1
MyThread7.java

package com.zjns.test.mutilthread;public class MyThread7 extends Thread {    private boolean isRunning = true;    public boolean isRunning() {        return isRunning;    }    public void setRunning(boolean isRunning) {        this.isRunning = isRunning;    }    @Override    public void run() {        System.out.println("进入run了");        while(isRunning) {        }        System.out.println("线程被停止了");    }}

Run5.java

package com.zjns.test.mutilthread;public class Run5 {    public static void main(String[] args) {        try {            MyThread7 thread7 = new MyThread7();            thread7.start();            Thread.sleep(1000);            thread7.setRunning(false);            System.out.println("已经赋值为false");        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

运行结果是死循环了,thread7.setRunning(false);失效,原因是设置的false是公共堆栈的值,线程私有数据栈并没有改变,而线程取的是线程私有数据栈的值。将MyThread7.java中的private boolean isRunning = true;改为volatile private boolean isRunning = true;可以使得读取的值是公共堆栈中的值,就不会死循环了。

volatile缺点

  • 不支持原子性
  • 只能修饰变量,不能修饰方法和代码块

volatile解决的是变量在多线程之间的可见性;而synchronized解决的是多线程之间访问资源的同步性。

AtomicInteger并不完全安全

addAndGet方法本身是原子的

AtomicInteger atomicInteger = new AtomicInteger();atomicInteger.addAndGet(1);

但是addAndGet和addAndGet之间并不同步

AtomicInteger atomicInteger = new AtomicInteger();atomicInteger.addAndGet(1);atomicInteger.addAndGet(100);
0 0