欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详谈Java多线程的几个常用关键字

程序员文章站 2024-02-28 11:10:46
一、同步(synchronized)和异步(asynchronized) 1、同步(synchronized)简单说可以理解为共享的意思,如果资源不是共享的,就没必要进行...

一、同步(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则可实现线程的安全性。

以上这篇详谈java多线程的几个常用关键字就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。