詳談Java多線程的幾個(gè)常用關(guān)鍵字
一、同步(synchronized)和異步(asynchronized)
1、同步(synchronized)簡(jiǎn)單說可以理解為共享的意思,如果資源不是共享的,就沒必要進(jìn)行同步。設(shè)置共享資源為同步的話,可以避免一些臟讀情況。
2、異步(asynchronized)簡(jiǎn)單說可以理解為獨(dú)立不受到其他任何制約。
舉個(gè)例子:
線程1調(diào)用了帶有synchronized關(guān)鍵字的方法methodA,線程2調(diào)用了異步方法methodB,出現(xiàn)的現(xiàn)象是同時(shí)控制臺(tái)輸出 t1,t2。
package com.ietree.multithread.sync; /** * 多線程之對(duì)象同步鎖和異步鎖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調(diào)用了帶有synchronized關(guān)鍵字的方法methodA,線程2調(diào)用了帶有synchronized關(guān)鍵字的方法methodB,出現(xiàn)的現(xiàn)象是首先輸出t1,等待4秒之后再輸出t2。
package com.ietree.multithread.sync; /** * 多線程之對(duì)象同步鎖和異步鎖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()); } }
結(jié)論:
在第一段代碼中t1線程先持有object對(duì)象的Lock鎖,t2線程可以以異步的方式調(diào)用對(duì)象中的非synchronized修飾的方法,所以同時(shí)輸出;
在第二段代碼中t1線程先持有object對(duì)象的Lock鎖,t2線程如果在這個(gè)時(shí)候調(diào)用對(duì)象中的同步(synchronized)方法則需等待,也就是同步。
二、volatile
作用:volatile關(guān)鍵字的作用是:使變量在多個(gè)線程間可見(具有可見性),但是僅靠volatile是不能保證線程的安全性,volatile關(guān)鍵字不具備synchronized關(guān)鍵字的原子性。
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("進(jìn)入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的值已經(jīng)被設(shè)置了false"); } }
程序輸出:
進(jìn)入run方法.. isRunning的值已經(jīng)被設(shè)置了false 之后進(jìn)入死循環(huán)
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("進(jìn)入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的值已經(jīng)被設(shè)置了false"); } }
程序輸出:
isRunning的值已經(jīng)被設(shè)置了false 線程停止
總結(jié):當(dāng)多個(gè)線程之間需要根據(jù)某個(gè)條件確定 哪個(gè)線程可以執(zhí)行時(shí),要確保這個(gè)條件在 線程之間是可見的。因此,可以用volatile修飾。
volatile 與 synchronized 的比較:
①volatile輕量級(jí),只能修飾變量。synchronized重量級(jí),還可修飾方法
②volatile只能保證數(shù)據(jù)的可見性,不能用來同步,因?yàn)槎鄠€(gè)線程并發(fā)訪問volatile修飾的變量不會(huì)阻塞。
synchronized不僅保證可見性,而且還保證原子性,因?yàn)椋挥蝎@得了鎖的線程才能進(jìn)入臨界區(qū),從而保證臨界區(qū)中的所有語句都全部執(zhí)行。多個(gè)線程爭(zhēng)搶synchronized鎖對(duì)象時(shí),會(huì)出現(xiàn)阻塞。
線程安全性包括兩個(gè)方面,①可見性。②原子性。
從上面自增的例子中可以看出:僅僅使用volatile并不能保證線程安全性。而synchronized則可實(shí)現(xiàn)線程的安全性。
以上這篇詳談Java多線程的幾個(gè)常用關(guān)鍵字就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringCloud使用Nacos保存和讀取變量的配置方法
在使用SpringCloud開發(fā)微服務(wù)時(shí),經(jīng)常會(huì)遇到一些比較小的后臺(tái)參數(shù)配置,這些配置不足以單獨(dú)開一張表去存儲(chǔ),而且其他服務(wù)會(huì)讀取該參數(shù),這篇文章主要介紹了SpringCloud使用Nacos保存和讀取變量,需要的朋友可以參考下2022-07-07springboot 使用zookeeper實(shí)現(xiàn)分布式隊(duì)列的基本步驟
這篇文章主要介紹了springboot 使用zookeeper實(shí)現(xiàn)分布式隊(duì)列,通過ZooKeeper的協(xié)調(diào)和同步機(jī)制,多個(gè)應(yīng)用程序可以共享一個(gè)隊(duì)列,并按照先進(jìn)先出的順序處理隊(duì)列中的消息,需要的朋友可以參考下2023-08-08Springboot繼承Keycloak實(shí)現(xiàn)單點(diǎn)登錄與退出功能
這篇文章主要介紹了Springboot繼承Keycloak實(shí)現(xiàn)單點(diǎn)登陸與退出,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08