synchronized和volatile使用

Posted vincentyw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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();
    }
}

以上是关于synchronized和volatile使用的主要内容,如果未能解决你的问题,请参考以下文章

synchronized和volatile

synchronized同步块和volatile同步变量

volatile和Sychronized

synchronized和volatile的区别

volatile和synchronized

描述static, final, synchronized, volatile的作用