java線程同步操作實例詳解
本文實例講述了java線程同步操作。分享給大家供大家參考,具體如下:
java線程同步
public class Hello {
public static void main(String[] args) {
MyRun myRun0 = new MyRun();
new Thread(myRun0, "Thread0").start();
new Thread(myRun0, "Thread1").start();
new Thread(myRun0, "Thread2").start();
}
}
class MyRun implements Runnable {
private int k = 0;
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "**********" + i);
k++;
if (k <= 3) {
if ("Thread0".equals(Thread.currentThread().getName())) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "," + k);
}
}
}
}
輸出結(jié)果
Thread0**********0
Thread1**********0
Thread2**********0
Thread1,2
Thread2,3
Thread1**********1
Thread2**********1
Thread2**********2
Thread1**********2
Thread0,7
Thread0**********1
Thread0**********2
說明多線程在某些場景是存在問題的,有時候需要線程同步。
同步 synchronized
同步代碼塊,synchronized(obj){},obj是一個對象,在這里就相當(dāng)于一把鎖,表示一旦有進(jìn)程搶到了這把鎖的鑰匙(就是進(jìn)入了代碼塊),其他進(jìn)程將無法進(jìn)入該鎖的代碼塊(當(dāng)前代碼塊其他進(jìn)程一定是進(jìn)不來了,其他地方的代碼塊如果也是用了這把鎖,同樣進(jìn)不去),只有代碼塊執(zhí)行完,釋放鎖后,所有進(jìn)程再重新?lián)岃€匙。
注意,上同一把鎖的代碼塊都會被鎖住,這些代碼塊可能寫在不同方法不同位置上。
被同步代碼塊包住的代碼多個線程只能順次進(jìn)入。
synchronized (this) {
k++;
if (k <= 3) {
if ("Thread0".equals(Thread.currentThread().getName())) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "," + k);
}
}
this表示當(dāng)前對象,這里考慮的只是運行這個方法,不涉及其它類也不涉及這個類的其它地方需要同步問題,所以用this也是可以的。k增加和輸出一個流程內(nèi)只能有一個線程在訪問,所以可以得到想要的輸出結(jié)果
輸出結(jié)果
Thread0**********0
Thread1**********0
Thread2**********0
Thread0,1
Thread0**********1
Thread2,2
Thread2**********1
Thread1,3
Thread1**********1
Thread0**********2
Thread2**********2
Thread1**********2
對方法進(jìn)行同步,如果存在多線程,每個線程順次訪問該方法
注意,如果一個類里面存在多個同步方法,那么這些同步方法的鎖是一個,都是當(dāng)前對象,所以不同線程想同時訪問同一對象的不同方法也是不行的,因為這些方法都上了同一把鎖,但是鑰匙只有一把,只能一個線程持有。
@Override
public synchronized void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "**********" + i);
k++;
if (k <= 3) {
if ("Thread0".equals(Thread.currentThread().getName())) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "," + k);
}
}
}
輸出結(jié)果
Thread0**********0
Thread0,1
Thread0**********1
Thread0,2
Thread0**********2
Thread0,3
Thread2**********0
Thread2**********1
Thread2**********2
Thread1**********0
Thread1**********1
Thread1**********2
死鎖
public class Hello {
public static void main(String[] args) {
A a = new A();
B b = new B();
new Thread(new MyRun(a,b)).start();
new Thread(new MyRun1(a,b)).start();
}
}
class MyRun implements Runnable{
private A a;
private B b;
public MyRun(A a, B b) {
this.a = a;
this.b = b;
}
@Override
public void run(){
a.say(b);
}
}
class MyRun1 implements Runnable {
private A a;
private B b;
public MyRun1(A a, B b) {
this.a = a;
this.b = b;
}
@Override
public void run() {
b.say(a);
}
}
class A{
public synchronized void say(B b){
System.out.println("A要知道B的信息");
b.info();
}
public synchronized void info(){
System.out.println("這是A");
}
}
class B{
public synchronized void say(A a){
System.out.println("B要知道A的信息");
a.info();
}
public synchronized void info(){
System.out.println("這是B");
}
}
如果兩個線程同時進(jìn)入了兩個say方法,就是出現(xiàn)死鎖。
關(guān)鍵點在于一個對象的多個同步方法具有相同的鎖,都是當(dāng)前對象。也就是x線程在訪問a對象的say方法過程中,y線程是無法訪問a對象的info方法的,因為開鎖的鑰匙已經(jīng)被x線程搶占了。
上面的程序,如果線程x,y同時進(jìn)入了兩個say方法,a對象同步方法的鎖被線程x搶占,b對象同步方法的鎖被線程y搶占,此時線程x無法訪問b對象的同步方法,線程y無法訪問a對象的同步方法。代碼中恰好想要訪問,所以就出現(xiàn)死鎖了。
更多java相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Java進(jìn)程與線程操作技巧總結(jié)》、《Java數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Java操作DOM節(jié)點技巧總結(jié)》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總》
希望本文所述對大家java程序設(shè)計有所幫助。
相關(guān)文章
jxl 導(dǎo)出數(shù)據(jù)到excel的實例講解
下面小編就為大家分享一篇jxl 導(dǎo)出數(shù)據(jù)到excel的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12
Java?GUI實現(xiàn)學(xué)生成績管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java?GUI實現(xiàn)學(xué)生成績管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01
Java基于遞歸和循環(huán)兩種方式實現(xiàn)未知維度集合的笛卡爾積算法示例
這篇文章主要介紹了Java基于遞歸和循環(huán)兩種方式實現(xiàn)未知維度集合的笛卡爾積算法,結(jié)合實例形式分析了Java使用遞歸與循環(huán)兩種方式實現(xiàn)未知維度集合的笛卡爾積相關(guān)概念、原理與操作技巧,需要的朋友可以參考下2017-12-12
spring boot2結(jié)合mybatis增刪改查的實現(xiàn)
這篇文章主要給大家介紹了關(guān)于spring boot2結(jié)合mybatis增刪改查的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用spring boot2具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
idea將maven項目改成Spring boot項目的方法步驟
這篇文章主要介紹了idea將maven項目改成Spring boot項目的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
Springboot整合MybatisPlus的實現(xiàn)過程解析
這篇文章主要介紹了Springboot整合MybatisPlus的實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-10-10

