日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

并发编程-同步机制(一)

發布時間:2023/12/8 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 并发编程-同步机制(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、synchronized 內置鎖

java 關鍵字synchronized 用于保證線程對變量訪問的可見性與排他性,又可以稱之為內置鎖機制。

synchronized 可以修飾方法跟同步塊上來進行使用,確保多個線程只有一個線程處于方法或者同步塊中。

同步方法與同步塊

使用 前面學習過的CountDownLatch 做并發測試

import java.util.concurrent.CountDownLatch;/*** 演示synchronized 同步方法,同步塊基本使用方法* * @author ckj**/ public class SynchronizedTest {static CountDownLatch latch = new CountDownLatch(10);private Object obj = new Object();private int num = 0;/*** 同步方法加鎖*/public synchronized void synIncNum() {num++;}/*** 同步塊加鎖*/public void synIncNum2() {synchronized(this) {num++;}//也可以寫成這樣 // synchronized(obj) { // num++; // }}public void incNum() {num++;}static class MyThread extends Thread {private SynchronizedTest syn;public MyThread(SynchronizedTest syn) {this.syn = syn;}public void run() {for (int i = 0; i < 10000; i++) {//幾個測試方法自己手動去切換測試syn.incNum();//syn.synIncNum();//syn.synIncNum2();}latch.countDown();};}public static void main(String[] args) throws InterruptedException {SynchronizedTest syn = new SynchronizedTest();//啟動10個線程滿足latch 計數器for(int i =0 ;i<10;i++) {new MyThread(syn).start();}latch.await();System.out.println(syn.num); //理想值應該是100000}}

從測試類的測試結果可以看的出來,如果沒有加同步機制在多線程的情況下會出現并發問題。

那么synchronized 到底鎖的是什么呢。 從上面的例子看來synchronized 鎖的是其實就是對象

其實你可以認為在方法上使用synchronized關鍵字其實他的含義就是synchronized(this) 。從這個方向去理解synchronized鎖的話那么synchronized鎖不同對象的話那么線程就可以并行了。

對象鎖

/*** 演示鎖的對象不同線程并行* * @author ckj**/ public class InstanceSynTest {static class MyThread implements Runnable {private InstanceSynTest syn;public MyThread(InstanceSynTest syn) {this.syn = syn;}public void run() {System.out.println("開始執行MyThread" + Thread.currentThread().getName());syn.syncInstance1();}}static class MyThread2 implements Runnable {private InstanceSynTest syn;public MyThread2(InstanceSynTest syn) {this.syn = syn;}public void run() {System.out.println("開始執行MyThread2" + Thread.currentThread().getName());syn.syncInstance2();}}public synchronized void syncInstance1() {try {Thread.sleep(2000);System.out.println("syncInstance1 開始執行..." + this.toString());Thread.sleep(2000);System.out.println("syncInstance1 結束執行 " + this.toString());} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public synchronized void syncInstance2() {try {Thread.sleep(2000);System.out.println("synInstance2 開始執行..." + this.toString());Thread.sleep(2000);System.out.println("synInstance2 結束執行 " + this.toString());} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static void main(String[] args) throws InterruptedException {InstanceSynTest ins1 = new InstanceSynTest();InstanceSynTest ins2 = new InstanceSynTest();Thread thread1 = new Thread(new MyThread(ins1));Thread thread2 = new Thread(new MyThread2(ins2)); // 由于傳入的對象是不同對象,線程執行的順序是并行的//Thread thread2 = new Thread(new MyThread2(ins1)); // 修改為同一對象的話那么,線程執行變為串行thread1.start();thread2.start();Thread.sleep(6000);} }

如果我我們把鎖加在static 方法上面呢,那么又會是說明結果。我們知道類的對象可以有許多,但是類只有一個class 對象只有一個,所以不同對象實例的對象鎖是是互不干擾的,但是每個類都只有一個類鎖。但是有一點類鎖只是概念上的東西。

類鎖

稍微修改上面測試類

/*** 演示實例鎖和類鎖的不同,可以并行開始 * * @author ckj**/ public class InstanceClassSynTest {static class MyThread implements Runnable {private InstanceClassSynTest syn;public MyThread(InstanceClassSynTest syn) {this.syn = syn;}public void run() {System.out.println("開始執行MyThread" + Thread.currentThread().getName());syn.syncInstance1();}}static class MyThread2 implements Runnable {public void run() {System.out.println("開始執行MyThread2" + Thread.currentThread().getName());syncInstance2();}}public synchronized void syncInstance1() {try {Thread.sleep(2000);System.out.println("syncInstance1 開始執行..." + this.toString());Thread.sleep(2000);System.out.println("syncInstance1 結束執行 " + this.toString());} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static synchronized void syncInstance2() {try {Thread.sleep(2000);System.out.println("synInstance2 開始執行...");Thread.sleep(2000);System.out.println("synInstance2 結束執行 " );} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public static void main(String[] args) throws InterruptedException {InstanceClassSynTest ins1 = new InstanceClassSynTest();Thread thread1 = new Thread(new MyThread(ins1));Thread thread2 = new Thread(new MyThread2()); // 由于傳入的對象是不同對象,線程執行的順序是并行的thread1.start();thread2.start();Thread.sleep(6000);} }

下面演示一個比較經典的錯誤加鎖的案例

/*** 演示錯誤加鎖* * @author ckj**/ public class IntegerSynTest {static class MyThread implements Runnable {private Integer i;public MyThread(Integer i) {this.i = i;}public void run() {synchronized (i) {Thread thread = Thread.currentThread();i++;System.out.println(i);try {thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}public static void main(String[] args) {MyThread myThread = new MyThread(1);for(int i = 0;i<5;i++) {new Thread(myThread).start();}}}

按照我們預期結果的話輸入應該是

2
3
4
5
6

結果應該如上是2->3->4->5->6

實際結果是:

4
6
5
4
4
那哪里出問題了呢

增加日記打印

public void run() {synchronized (i) {Thread thread = Thread.currentThread();i++;System.out.println(thread.getName()+"-------"+i+"-@"+System.identityHashCode(i)+"----------"+"-@"+System.identityHashCode(this));try {thread.sleep(1000);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}

System.identityHashCode 方法打印出原生Object 的hashCode 可以認為他是內存地址

Thread-1-------3-@1073512853-----------@825980954
Thread-2-------4-@923214033-----------@825980954
Thread-3-------5-@1428845299-----------@825980954
Thread-4-------6-@1534375319-----------@825980954
Thread-0-------3-@1073512853-----------@825980954
發現了原來 i 的對象一直在變,每次鎖的對象都發生的變化當然得不到預期結果咯,那么為什么會這樣呢。通過反編譯工具打開class 類

public void run(){synchronized (this.i){Thread thread = Thread.currentThread();this.i = Integer.valueOf(this.i.intValue() + 1);System.out.println(thread.getName() + "-------" + this.i + "-@" + System.identityHashCode(this.i) + "----------" + "-@" + System.identityHashCode(this));try{Thread.sleep(1000L);}catch (Exception e){e.printStackTrace();}}}}

發現他調用了Integer.valueof 方法,查看一下

public static Integer valueOf(String s, int radix) throws NumberFormatException {return Integer.valueOf(parseInt(s,radix));}public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}

他重新new 了一個出來,所以鎖不住了。

那我們怎么處理呢?上面打印結果就可以看出了,我們直接鎖this 對象就可以解決問題了。

public void run() {synchronized (this) {Thread thread = Thread.currentThread();i++;System.out.println(thread.getName()+"-------"+i+"-@"+System.identityHashCode(i)+"----------"+"-@"+System.identityHashCode(this));try {thread.sleep(1000);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}


?

總結

以上是生活随笔為你收集整理的并发编程-同步机制(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。