疯狂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则可实现线程的安全性。