zoukankan      html  css  js  c++  java
  • Java多线程的几个常用关键字

    一、同步(synchronized)和异步(asynchronized)

      1、同步(synchronized)简单说可以理解为共享的意思,如果资源不是共享的,就没必要进行同步。设置共享资源为同步的话,可以避免一些脏读情况。

      2、异步(asynchronized)简单说可以理解为独立不受到其他任何制约。

    举个例子:

    线程1调用了带有synchronized关键字的方法methodA,线程2调用了异步方法methodB,出现的现象是同时控制台输出 t1,t2。

    package com.ietree.multithread.sync;
    
    /**
     * 多线程之对象同步锁和异步锁Demo
     *
     * @author ietree
     */
    public class SynAndAsynDemo {
    
        public static void main(String[] args) {
            
            final SynAndAsynDemo mo = new SynAndAsynDemo();
            
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    mo.methodA();
                }
            },"t1");
            
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    mo.methodB();
                }
            },"t2");
            
            t1.start();
            t2.start();
        }
        
        // 方法A
        public synchronized void methodA(){
            try {
                System.out.println(Thread.currentThread().getName());
                // 休眠4秒
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        // 方法B
        public void methodB(){
            System.out.println(Thread.currentThread().getName());
        }
        
    }

    线程1调用了带有synchronized关键字的方法methodA,线程2调用了带有synchronized关键字的方法methodB,出现的现象是首先输出t1,等待4秒之后再输出t2。

    package com.ietree.multithread.sync;
    
    /**
     * 多线程之对象同步锁和异步锁Demo
     *
     * @author ietree
     */
    public class SynAndAsynDemo {
    
        public static void main(String[] args) {
            
            final SynAndAsynDemo mo = new SynAndAsynDemo();
            
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    mo.methodA();
                }
            },"t1");
            
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    mo.methodB();
                }
            },"t2");
            
            t1.start();
            t2.start();
        }
        
        // 方法A
        public synchronized void methodA(){
            try {
                System.out.println(Thread.currentThread().getName());
                // 休眠4秒
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        // 方法B
        public synchronized void methodB(){
            System.out.println(Thread.currentThread().getName());
        }
        
    }

    结论:

    在第一段代码中t1线程先持有object对象的Lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法,所以同时输出;

    在第二段代码中t1线程先持有object对象的Lock锁,t2线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步。

    二、volatile

    作用:volatile关键字的作用是:使变量在多个线程间可见(具有可见性),但是仅靠volatile是不能保证线程的安全性,volatile关键字不具备synchronized关键字的原子性。

    Demo1:

    package com.ietree.multithread.sync;
    
    public class RunThread extends Thread {
        // volatile
        private boolean isRunning = true;
    
        private void setRunning(boolean isRunning) {
            this.isRunning = isRunning;
        }
    
        public void run() {
            System.out.println("进入run方法..");
            int i = 0;
            while (isRunning == true) {
                // ..
            }
            System.out.println("线程停止");
        }
    
        public static void main(String[] args) throws InterruptedException {
            RunThread rt = new RunThread();
            rt.start();
            Thread.sleep(1000);
            rt.setRunning(false);
            System.out.println("isRunning的值已经被设置了false");
        }
    }

    程序输出:

    进入run方法..
    isRunning的值已经被设置了false
    
    之后进入死循环

    Demo2:

    package com.ietree.multithread.sync;
    
    public class RunThread extends Thread {
        // volatile
        private volatile boolean isRunning = true;
    
        private void setRunning(boolean isRunning) {
            this.isRunning = isRunning;
        }
    
        public void run() {
            System.out.println("进入run方法..");
            int i = 0;
            while (isRunning == true) {
                // ..
            }
            System.out.println("线程停止");
        }
    
        public static void main(String[] args) throws InterruptedException {
            RunThread rt = new RunThread();
            rt.start();
            Thread.sleep(1000);
            rt.setRunning(false);
            System.out.println("isRunning的值已经被设置了false");
        }
    }

    程序输出:

    isRunning的值已经被设置了false
    线程停止

    总结:当多个线程之间需要根据某个条件确定 哪个线程可以执行时,要确保这个条件在 线程之间是可见的。因此,可以用volatile修饰。

    volatile 与 synchronized 的比较:

    ①volatile轻量级,只能修饰变量。synchronized重量级,还可修饰方法

    ②volatile只能保证数据的可见性,不能用来同步,因为多个线程并发访问volatile修饰的变量不会阻塞。

    synchronized不仅保证可见性,而且还保证原子性,因为,只有获得了锁的线程才能进入临界区,从而保证临界区中的所有语句都全部执行。多个线程争抢synchronized锁对象时,会出现阻塞。

    线程安全性包括两个方面,①可见性。②原子性。

    从上面自增的例子中可以看出:仅仅使用volatile并不能保证线程安全性。而synchronized则可实现线程的安全性。

  • 相关阅读:
    [SPOJ-TTM]To the moon
    [BZOJ1901]Zju2112 Dynamic Rankings
    [算法模板]ST表
    [算法模板]树状数组
    [SPOJ-COT]Count on a tree
    [算法模板]倍增求LCA
    【bzoj 3433】{Usaco2014 Jan} Recording the Moolympics(算法效率--贪心)
    【uva 1152】4 Values Whose Sum is Zero(算法效率--中途相遇法+Hash或STL库)
    【uva 658】It's not a Bug, it's a Feature!(图论--Dijkstra或spfa算法+二进制表示+类“隐式图搜索”)
    【uva 10048】Audiophobia(图论--Floyd算法)
  • 原文地址:https://www.cnblogs.com/Dylansuns/p/6701511.html
Copyright © 2011-2022 走看看