synchronized和volatile使用

synchronized和volatile

volatile :保证内存可见性,但是不保证原子性;

synchronized:同步锁,既能保证内存可见性,又能保证原子性;

synchronized实现可重入锁 (1.持有同一锁自动获取   2.继承锁)

锁定的对象有两种:1.类的实例(对象锁) 2.类对象(类锁)

对象锁(synchronized修饰普通方法或代码块)    对象锁已被其他调用者占用,则需要等待此锁被释放 

/**
* 对象锁的两种方式
*/
//方式一

private int count =10;
public synchronized void test01() {
count--;
System.out.println(Thread.currentThread().getName()+"count="+count);
}

//方式二
public void test02() {
synchronized(this) {
count--;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
}

类锁(synchronized修饰静态方法)   所有类实例化对象互斥拥有一把类锁

private static int count =10;
    /**
     * 类锁两种表现方式
     */
    public static synchronized void test01() {
        count -- ;
        System.out.println(Thread.currentThread().getName()+"count="+count);
    }

    public static  void test02() {
        synchronized(CurrentDemo01.class) {
            count -- ;
            System.out.println(Thread.currentThread().getName()+"count="+count);
        }
    }

同一字符串常量代表同一把锁对象

//t1执行结束,t2再执行,t1和t2持有同一把锁
public class CurrentDemo03 {

    String s1 = "yew";
    String s2 = "yew";

    public void test01(){
        synchronized (s1){
            System.out.println(Thread.currentThread().getName()+"---start");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                System.out.println("interrupt");
            }
            System.out.println(Thread.currentThread().getName()+"---end");
        }
    }

    public void test02(){
          synchronized (s2){
              System.out.println(Thread.currentThread().getName()+"---start");
              try {
                  TimeUnit.SECONDS.sleep(1);
              } catch (InterruptedException e) {
                  System.out.println("interrupt");
              }
              System.out.println(Thread.currentThread().getName()+"---end");
          }
    }

    public static void main(String[] args) {
        CurrentDemo03 demo3 = new CurrentDemo03();
        new Thread(demo3::test01,"t1").start();
        new Thread(demo3::test02,"t2").start();
    }
}

synchronized同步代码块粒度越小,执行效率越高

public class CurrentDemo04 {

 //总数
 private static int count = 0;
 public synchronized  void test01() throws InterruptedException {
     System.out.println(Thread.currentThread().getName()+"---start");
     TimeUnit.SECONDS.sleep(2);
     for (int i = 0; i <10000000 ; i++) {
         count++ ;
     }
     TimeUnit.SECONDS.sleep(2);
     System.out.println(Thread.currentThread().getName()+"---end");
 }

 public void test02() throws InterruptedException {
     System.out.println(Thread.currentThread().getName()+"---start");
     TimeUnit.SECONDS.sleep(2);
     synchronized (this){
         for (int i = 0; i <10000000 ; i++) {
             count++ ;
         }
     }
     TimeUnit.SECONDS.sleep(2);
     System.out.println(Thread.currentThread().getName()+"---end");
 }

    //demo04.test01();8043ms
    // demo04.test02();4116ms
    public static void main(String[] args){
        CurrentDemo04 demo04 = new CurrentDemo04();
        long start = System.currentTimeMillis();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo04.test02();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo04.test02();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        System.out.println(Thread.activeCount());
        while(Thread.activeCount()>2){
            Thread.yield();
        }
        long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-start)+"ms");
        System.out.println(count);
    }
}

synchronized方法正常返回或者抛异常而终止,jvm会自动释放对象锁(捕获异常则不会自动释放)

public class CurrentDemo08 {

    //总数值
    private int count = 0;

    public synchronized void test01() throws Exception {
        System.out.println(Thread.currentThread().getName()+"---start");

        while (true){
            count++ ;
            TimeUnit.SECONDS.sleep(1);
            if(count <5){
                System.out.println(count);
            }else{
                try {
                    int m =  count/0;
                }catch (Exception e){
                    System.out.println("ERROR :"+e.getMessage());
                   // return;
                }
            }
        }
    }

    public synchronized void test02() throws InterruptedException {
        System.out.println(Thread.currentThread().getName()+"----start");

        TimeUnit.SECONDS.sleep(1);
        System.out.println(Thread.currentThread().getName()+"---end");
    }

    public static void main(String[] args) {

        CurrentDemo08 demo08 = new CurrentDemo08();

        new Thread(()-> {
            try {
                demo08.test01();
            } catch (Exception e) {
                System.out.println("test01中断");
            }
        },"t1").start();

        new Thread(()-> {
            try {
                demo08.test02();
            } catch (InterruptedException e) {
                System.out.println("test02中断");
            }
        },"t2").start();
    }
}
/**
 * @author yew
 * @date on 2019/11/18 - 11:49
 * 一道面试题:实现一个容器,提供两个方法,add,size
 * 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,
 * 当个数到5个时,线程2给出提示并结束线程2
 * 1.无volatile,线程间不可见,线程t2不会结束
 * 2.volatile可以保证原子的可见性,存在不确定性  while(true) 占用CPU资源
 */
public class CurrentDemo11 {
   //List<Object> lists = new ArrayList<Object>();
    volatile List<Object> lists = new ArrayList<Object>();

    public void add(Object s) {
        lists.add(s);
    }
    public int size() {
        return lists.size();
    }

    public static void main(String[] args) {
        CurrentDemo11 demo11 = new CurrentDemo11();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                demo11.add(new Object());
                System.out.println("add Object" + (i + 1));
                try {
                    TimeUnit.MILLISECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("t1线程结束");
        }, "t1").start();

        new Thread(() -> {
            System.out.println("t2线程开始");
            while (true) {
                if (demo11.size() == 5){
                    break;
                }
            }
            System.out.println("t2线程结束");
        }, "t2").start();
    }
}

优化上述问题:
/** * @author yew * 1.wait----notify(随机唤醒持有当前锁且等待的某个线程)/notifyAll(唤醒持有当前锁所有的等待线程) * notify随机唤醒持有锁等待的线程,但是不会释放当前持有的锁 所以监控线程不会立马结束 * 2.countdownLatch */public class CurrentDemo12 {

     List lists = new ArrayList();

    public int size() {        return this.lists.size();    }

    public void add(Object obj) {        this.lists.add(obj);    }

    public static void main(String[] args) {        CurrentDemo12 demo12 = new CurrentDemo12();

        Object lock = new Object();

        //先启用t2进行监听        new Thread(()->{            synchronized (lock){                System.out.println("t2线程启动");                if(demo12.size() != 5){                    try {                        lock.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                System.out.println("t2线程结束");                lock.notify();            }

        },"t2").start();

        new Thread(()->{            synchronized (lock){                System.out.println("t1线程启动");                for (int i = 0; i < 10 ; i++) {                    System.out.println("add Object"+(i+1));                    demo12.add(new Object());                    try {                        TimeUnit.SECONDS.sleep(1);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    if(demo12.size() == 5){                        lock.notify();                        try {                            lock.wait();                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                    }                }                System.out.println("t1线程结束");            }        }).start();    }}
/** * 面试题:写一个固定容量同步容器,拥有Put和get方法,以及getCount方法,
 * 能够支持两个生产者线程以及10个消费者线程的阻塞调用
 * wait notifyAll
 */
public class CurrentDemo13 {
    private static final  int MAX = 20;
    private final LinkedList<Object> list = new LinkedList<>();
    static int count;

    public synchronized void put(Object obj){
        while (list.size() == MAX){
            try {
                this.wait();
            } catch (InterruptedException e) {
                System.out.println();
            }
        }
        list.add(obj);
        ++count;
        System.out.println("生产后剩余数量"+count);
        this.notifyAll();
    }

    public synchronized  Object get(){
        while (list.size()==0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Object t = list.removeFirst();
        --count;
        System.out.println("消费后剩余数量"+count);
        this.notifyAll();
        return t;
    }

    public int getCount(){
        return count;
    }

    public static void main(String[] args) {
        CurrentDemo13 demo13 = new CurrentDemo13();
        //创建生产者
        for (int i = 0; i < 2; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true){
                        demo13.put(Thread.currentThread().getName()+"---"+count);
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true){
                        System.out.println(demo13.get());
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }
}
/** * condition:在某种状态下 */public class CurrentDemo14 {    LinkedList<Object> lists = new LinkedList<>();    private static final int MAX = 20;    private  static int count = 0;    ReentrantLock lock = new ReentrantLock();    Condition producer = lock.newCondition();    Condition consumer = lock.newCondition();

    public  void put(Object obj){

        try {            lock.lock();            while (lists.size()==MAX){                producer.await();            }            lists.add(obj+"----"+count);            count++;            System.out.println("生产后剩余:"+count);            Thread.sleep(500);            consumer.signalAll();        } catch (Exception e) {            System.out.println("生产线程异常中断"+e.getMessage());        }finally {            lock.unlock();        }    }

    public  Object get(){        Object t = null;        try {            lock.lock();            while (lists.size()==0){                consumer.await();            }            t = lists.removeFirst();            System.out.println("已消费对象:"+t);            count--;            System.out.println("消费后剩余:"+count);            Thread.sleep(2000);            producer.signalAll();        } catch (Exception e) {            System.out.println("消费线程异常中断"+e.getMessage());        }finally {            lock.unlock();            return t;        }    }

    public static void main(String[] args){        CurrentDemo14 currentDemo14 = new CurrentDemo14();        for (int i = 0; i < 2; i++) {            new Thread("p"+i){                public void run(){                    for (;;) {                        currentDemo14.put(Thread.currentThread().getName());                    }                }            }.start();        }        try {            Thread.sleep(2000);        } catch (InterruptedException e) {            e.printStackTrace();        }        for (int i = 0; i < 10; i++) {            new Thread("c"+i){                public void run(){                    for (;;) {                        currentDemo14.get();                    }                }            }.start();        }    }}
/**
 * ReentrantLock
 * ReentrantLock同synchronized效果相同
 * 1.synchronized遇到异常,自动释放锁,reentranLock需要手动释放锁,所以释放锁需要放在finally代码块执行;
 * 2.tryLock() 尝试拿锁,拿不到锁的时候可以根据返回的boolean值来决定是否继续执行
 * 3.lockInterruptibly()可以对线程中断做出反应
 */
public class CurrentDemo15 {

    ReentrantLock lock = new ReentrantLock();

    public void test01(){
        try{
            lock.lock();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"test 01");
            int t = 10/0;
        }catch (Exception e){
            System.out.println("ERROR");
        }finally {
            lock.unlock();
        }
    }

    public void test02(){
        try{
//            lock.tryLock(3, TimeUnit.SECONDS);
//            lock.lockInterruptibly();
            lock.lock();
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+"test 02");
        }catch (Exception e){
            System.out.println("ERROR");
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        CurrentDemo15 currentDemo15 = new CurrentDemo15();
        new Thread("t1"){
            public void run(){
                currentDemo15.test01();
            }
        }.start();

        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Thread t2 = new Thread("t2"){
            public void run(){
                currentDemo15.test02();
            }
        };
        t2.start();

        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.interrupt();
    }
}

原文地址:https://www.cnblogs.com/vincentYw/p/11834793.html

时间: 2024-08-30 09:57:03

synchronized和volatile使用的相关文章

java 语言多线程可见性(synchronized 和 volatile 学习)

共享变量可见性实现的原理 java 语言层面支持的可见性实现方式: synchronized volatile 1. synchronized 的两条规定: 1 线程解锁前,必须把共享变量的最新值刷新到主内存中. 2 线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值(加锁与解锁需要是同一锁) 线程解锁前对共享变量的修改在下次加锁时对其他线程可见. 2. volatile 实现可见性 深入来说,通过加入内存屏障和禁止重排序优化来实现 的. 对volatil

java多线程之内存可见性-synchronized、volatile

1.JMM:Java Memory Model(Java内存模型) 关于synchronized的两条规定: 1.线程解锁前,必须把共享变量的最新值刷新到主内存中 2.线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值(注意:加锁和解锁需要是同一把锁) 注:线程解锁前对共享变量的修改在下次加锁时对其他线程可见 2.线程执行互斥代码的过程: 1.获得互斥锁 2.清空工作内存 3.从主内存拷贝变量的最新副本到工作内存 4.执行代码 5.将更改后的共享变量的值刷

synchronized和volatile的使用方法以及区别

先看看下面的例子: public class ThreadTest { public static void main(String[] args) { final Counter counter = new Counter(); for (int i = 0; i < 1000; i++) { new Thread(new Runnable() { @Override public void run() { counter.inc(); } }).start(); } System.out.p

Java中的synchronized、volatile、ReenTrantLock、AtomicXXX

多线程和并发性并不是什么新内容,但是 Java 语言设计中的创新之一就是,它是第一个直接把跨平台线程模型和正规的内存模型集成到语言中的主流语言.核心类库包含一个 Thread 类,可以用它来构建.启动和操纵线程,Java 语言包括了跨线程传达并发性约束的构造 -- synchronized 和 volatile .在简化与平台无关的并发类的开发的同时,它决没有使并发类的编写工作变得更繁琐,只是使它变得更容易了. synchronized 快速回顾 把代码块声明为 synchronized,有两个

关于synchronized与volatile的一点认识

贪婪是一种原罪,不要再追求性能的路上离正确越来越远. 内存模型 java内存模型 重排序 锁synchronized 什么是锁 独占锁 分拆锁 分离锁 分布式锁 volatile 内存模型 java内存模型 提到同步.锁,就必须提到java的内存模型,为了提高程序的执行效率,java也吸收了传统应用程序的多级缓存体系. 在共享内存的多处理器体系架构中,每个处理器都拥有自己的缓存,并且定期地与主内存进行协调.在不同的处理器架构中提供了不同级别的缓存一致性(Cache Coherence),其中一部

synchronized和volatile

简述synchronized和volatile的区别 1.synchronized可以使用在变量.方法.类级别,而volatile只能使用在变量级别 2.synchronized可以保证变量修改的可见性和原子性,而volatile只能保证变量修改的可见性 3.synchronized有可能造成线程的阻塞,而volatile不会 4.synchronized标记的变量会被编译器优化,而volatile标记的变量不会被优化 5.volatile的变量若与自身相关,如以下的声明方式:n=n+1,n++

Synchronized、volatile与锁

时间尚早,今天多写一点 温故知新(三) Synchronized与volatile Synchronized有以下两个含义: 一.一次只有一个线程可以执行代码的受保护部分 二.一个线程更改的数据对于其他线程是可见的 volatile只适合于控制对基本变量(int.boolean等)的单个实例的访问.当一个变量被声明为volatile,任何对该变量的写操作都会绕过高速缓存,直接写入主内存,而任何对改变量的读取也都绕过高速缓存,直接取自主内存.这表示所有线程在任何时候看到的volatile变量值都相

4个点说清楚Java中synchronized和volatile的区别

作者 : Hollis 回顾一下两个关键字:synchronized和volatile 1.Java语言为了解决并发编程中存在的原子性.可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如synchronized.volatile.final.concurren包等. 2.synchronized通过加锁的方式,使得其在需要原子性.可见性和有序性这三种特性的时候都可以作为其中一种解决方案,看起来是“万能”的.的确,大部分并发控制操作都能使用synchronized来完成. 3.volat

并发编程之关键字(synchronized、volatile)

并发编程主要设计两个关键字:一个是synchronized,另一个是volatile.下面主要讲解这两个关键字,并对这两个关机进行比较. synchronized synchronized是通过JMV种的monitorenter和monitorexit指令实现同步.monitorenter指令是在编译后插入到同步代码的开始位置,而monitorexit插入到同步代码的结束位置和异常位置.每一个对象都与一个monitor相关联,当monitor被只有后,它将处于锁定状态. 当一个线程试图访问同步代