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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java多线程之synchronized(二)

發布時間:2024/10/12 java 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java多线程之synchronized(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ?為了解決“非線程安全”帶來的問題,上一節中使用的辦法是用關鍵字synchronized修飾多個線程可能同時訪問到的方法,但是這樣寫是存在一定的弊端的,比如線程A調用一個用synchronized修飾的同步方法,這個方法要執行很長時間,那么其它的線程必須無條件的等線程A執行完釋放掉對象鎖,當然前提是其他的線程也要訪問這個同步方法。這種情況就可以用synchronized代碼塊來解決。在解決之前我先附上一段沒優化之前的方法,這樣就可以直觀的看到效果差異。

? ? 證明synchronized方法的弊端,代碼如下:

public class Entity {public static long beginTime1;public static long endTime1;public static long beginTime2;public static long endTime2; }
public class Task_Synchronized {private String getData1;private String getData2; //兩個子線程要調用的公共方法public synchronized void doLongTimeTask() {try {System.out.println("begin task");Thread.sleep(3000);
//getData1和getdata2實際過程中可以是兩個非常耗時的操作,這樣看起來效果更名getData1 = "長時間處理任務后從遠程返回的值1 threadName="+ Thread.currentThread().getName();getData2 = "長時間處理任務后從遠程返回的值2 threadName="+ Thread.currentThread().getName();System.out.println(getData1);System.out.println(getData2);System.out.println("end task");} catch (InterruptedException e) {e.printStackTrace();}} } public static void main(String[] args) throws InterruptedException {Task_Synchronized task = new Task_Synchronized();MyThread1 t1 = new MyThread1(task);t1.start();MyThread2 t2 = new MyThread2(task);t2.start();Thread.sleep(10000);// 因為線程1和線程2哪個先執行不一定,所以比較了一下時間,開始的時間取比較小的值,結束的時間取較大的值long beginTime = Entity.beginTime1;if (Entity.beginTime2 < Entity.beginTime1) {beginTime = Entity.beginTime2;}long endTime = Entity.endTime1;if (Entity.endTime2 > Entity.endTime1) {endTime = Entity.endTime2;}System.out.println("耗時" + (endTime - beginTime) / 1000 + "s");} //第一個線程public static class MyThread1 extends Thread {private Task_Synchronized task;public MyThread1(Task_Synchronized task) {super();this.task = task;}@Overridepublic void run() {super.run();Entity.beginTime1 = System.currentTimeMillis();task.doLongTimeTask();Entity.endTime1 = System.currentTimeMillis();}} //第二個線程public static class MyThread2 extends Thread {private Task_Synchronized task;public MyThread2(Task_Synchronized task) {super();this.task = task;}@Overridepublic void run() {// TODO Auto-generated method stubsuper.run();Entity.beginTime2 = System.currentTimeMillis();task.doLongTimeTask();Entity.endTime2 = System.currentTimeMillis();}} 

   ? 運行結果如下:從Task_Synchronized 類可以看出,synchronized修飾的是doLongTimeTask()方法,從執行結果也可以看出syschronized修飾方法的執行順序是這樣的:Thread—0必須把同步的方法全部執行完,釋放掉對象鎖之后,Thread—1才可以執行,也就是說無論哪個線程先搶上CPU,就要執行到底之后,另一個線程才可以上CPU執行,這樣執行下來用時間是6s。

? ? ? ??

? ? ? ? ?那么接下來看看用synchronized代碼塊怎么解決這個弊端,我寫了一個例子,如下:

public class Task_Synchronized {private String getData1;private String getData2; //沒有synchronized修飾public void doLongTimeTask() {try {System.out.println("begin task");Thread.sleep(3000);String privateGetData1 = "長時間處理的任務1 threadName="+ Thread.currentThread().getName();String privateGetData2 = "長時間處理的任務1 threadName="+ Thread.currentThread().getName();
//synchronized代碼塊synchronized (this) {getData1 = privateGetData1;getData2 = privateGetData2;}System.out.println(getData1);System.out.println(getData2);System.out.println("end task");} catch (InterruptedException e) {e.printStackTrace();}}}

   ?執行結果如下:只需要修改一下doLongTimeTask()這個方法即可,用synchronized代碼塊來代替synchronized修飾方法,從運行結果可以看到時間只用3s,時間縮短了是由于線程Thread—0訪問Task_Synchronized類的同步代碼塊時,線程Thread—1仍然可以訪問Task_Synchronized類里的非同步方法。在這里為什么會想到只同步變量getData1和getData2呢,我以前說過出現“非線程安全”的原因,其中有一個原因就是有多個線程同時訪問成員變量時可能會出現“臟讀”現象。

? ? ? ??

? ? ? ??但是還有兩個問題需要驗證,那就是syschronized代碼塊里的內容真的是同步執行的嗎?這個this真的代表當前類的對象鎖嗎?下面我寫了一個例子來驗證一下,如下:

public static void main(String[] args) {Task task = new Task();ThreadA a = new ThreadA(task);a.setName("A");ThreadB b = new ThreadB(task);b.setName("B");a.start();b.start();}public static class ThreadA extends Thread {private Task task;public ThreadA(Task task) {super();this.task = task;}@Overridepublic void run() {super.run();task.doLongTimeTask();}}public static class ThreadB extends Thread {private Task task;public ThreadB(Task task) {super();this.task = task;}@Overridepublic void run() {super.run();task.doLongTimeTask();}} }class Task {public void doLongTimeTask() {for (int i = 0; i < 100; i++) {System.out.println("noSynchronized threadName="+ Thread.currentThread().getName() + " i=" + (i + 1));}System.out.println("*********************************");synchronized (this) {for (int i = 0; i < 100; i++) {System.out.println("Synchronized threadName="+ Thread.currentThread().getName() + " i=" + (i + 1));}}}

  ? ?  運行結果如下:由圖(a)可以看出來,兩個線程在執行第一for循環的時候,是不同步交叉執行的,由圖b1、b2、c1、c2可以看出來線程A排隊執行完,線程B才開始執行,所以synchronized代碼塊是同步的。

? ??? ? ? ???

? ? ? ? ? ? ??圖(a) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖(b1) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??圖(b2) ??

?

? ??? ?

? ? ? ? ? ? ? ? 圖(c1) ? ? ? ? ? ? ? 圖(c2)

? ?那么怎么驗證synchronized使用的“對象監視器”是一個呢,也就是this代表的是當前類的對象鎖。需要證明只有一個線程釋放掉當前對象鎖,其它的線程才可以執行。我寫了一個例子,如下:

public static void main(String[] args) {MyService service = new MyService();ThreadA a = new ThreadA(service);a.setName("A");ThreadB b = new ThreadB(service);b.setName("B");a.start();b.start();}public static class ThreadA extends Thread {private MyService service;public ThreadA(MyService service) {super();this.service = service;}@Overridepublic void run() {super.run();service.serviceMethodA();}}public static class ThreadB extends Thread {private MyService service;public ThreadB(MyService service) {super();this.service = service;}@Overridepublic void run() {super.run();service.serviceMethodB(); }} }class MyService {public void serviceMethodA() {synchronized (this) {try {System.out.println("A begin time=" + System.currentTimeMillis());Thread.sleep(5000);System.out.println("A end time=" + System.currentTimeMillis());} catch (InterruptedException e) {e.printStackTrace();}}}public void serviceMethodB() {synchronized (this) {try {System.out.println("B begin time=" + System.currentTimeMillis());Thread.sleep(2000);System.out.println("B end time=" + System.currentTimeMillis());} catch (InterruptedException e) {e.printStackTrace();}}}    運行結果如下:從代碼上可以看出,兩個synchronized代碼塊里都有休眠方法,但是并沒有影響線程的執行順序,如果兩個this不是同一把對象鎖,那么在休眠的這段時間,線程肯定會出現交替執行的,從結果也可以看出來,線程A執行完之后,線程B才開始執行的,說明當線程A訪問MyService的同步代碼塊serviceMethodA的時候,線程B對同步代碼塊serviceMethodB的訪問將被阻塞。所以“對象監視器”是同一個。

?

?

?

?

??

?

轉載于:https://www.cnblogs.com/chentong/p/5654112.html

總結

以上是生活随笔為你收集整理的Java多线程之synchronized(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

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