多線程解決同步問題淺析


一,問題背景

1.為什么要引入多線程?

     用多線程只有一個目的,那就是更好的利用cpu的資源,因為所有的多線程代碼都可以用單線程來實現。說這個話其實只有一半對,因為反應“多角色”的程序代碼,最起碼每個角色要給他一個線程吧,否則連實際場景都無法模擬,當然也沒法說能用單線程來實現:比如最常見的“生產者,消費者模型”。

2.多線程、同步、並發概念:

多線程:指的是這個程序(一個進程)運行時產生了不止一個線程。
並行:多個cpu實例或者多台機器同時執行一段處理邏輯,是真正的同時。
並發:通過cpu調度算法,讓用戶看上去同時執行,實際上從cpu操作層面不是真正的同時。並發往往在場景中有公用的資源,那么針對這個公用的資源往往產生瓶頸,我們會用TPS或者QPS來反應這個系統的處理能力。

3.引入多線程后會帶來那些問題?

      java允許多線程並發控制,當多個線程同時操作一個可共享的資源變量時(如數據的增刪改查),將會導致數據不准確,相互之間產生沖突,因此加入同步鎖以避免在該線程沒有完成操作之前,被其他線程的調用,從而保證了該變量的唯一性和准確性。

以買票系統為例,我們發現不加控制多線程會出現超賣現象。

 1 public class RunnableImpl implements Runnable {
 2 
 3 private int ticket=100;
 4     @Override
 5     public void run() {
 6         while(true){
 7             if (ticket<=0){
 8                 break;
 9             }
10             try {
11                 Thread.sleep(200);
12                 String name = Thread.currentThread().getName();
13                 System.out.println("第"+name+"窗口正在賣出第"+(200-ticket+1)+"張票,剩余"+(--ticket)+"張");
14             } catch (InterruptedException e) {
15                 e.printStackTrace();
16             }
17 
18         }
19 
20 
21 
22     }
23 }

測試類:

1 public class originticket {
2     public static void main(String[] args) {
3         RunnableImpl runnable = new RunnableImpl();
4        new Thread(runnable,"一").start();
5        new Thread(runnable,"二").start();
6     }
7 }

 

結果顯示:

 

二,問題解決方案之synchronize代碼塊:

 1 public class RunnableImplsyn implements Runnable {
 2 
 3 private int ticket=200;
 4     @Override
 5     public void run() {
 6         while(true) {
 7             try {
 8                 Thread.sleep(200);
 9             } catch (InterruptedException e) {
10                 e.printStackTrace();
11             }
12             synchronized (this) {
13             if (ticket <= 0) {
14                 break;
15             }
16 
17 
18                     String name = Thread.currentThread().getName();
19                     System.out.println("第" + name + "窗口正在賣出第" + (200 - ticket + 1) + "張票,剩余" + (--ticket) + "張");
20 
21 
22             }
23         }
24 
25 
26     }
27 }

測試類:

1 public class synchronizeblockTicket {
2 
3     public static void main(String[] args) {
4         RunnableImplsyn runnableImplsyn = new RunnableImplsyn();
5         new Thread(runnableImplsyn,"一").start();
6         new Thread(runnableImplsyn,"二").start();
7     }
8 }

結果:

三,問題解決方案之synchronize方法:

這里抽取了方法,this代指:

 1 public class RunnableImplsynfn implements Runnable {
 2 
 3 private static int ticket=200;
 4     @Override
 5     public void run() {
 6        test();
 7    
 8     }
 9 
10 
11     private synchronized void test() {
12         while(true){
13             if (ticket<=0){
14                 break;
15             }
16             try {
17                 Thread.sleep(200);
18                 String name = Thread.currentThread().getName();
19                 System.out.println("第"+name+"窗口正在賣出第"+(200-ticket+1)+"張票,剩余"+(--ticket)+"張");
20             } catch (InterruptedException e) {
21                 e.printStackTrace();
22             }
23 
24         }
25 
26 
27 
28     }
29     }

測試類:

1 public class synchronizefnTicket {
2 
3 
4     public static void main(String[] args) {
5         RunnableImplsynfn runnableImplsyn = new RunnableImplsynfn();
6         new Thread(runnableImplsyn,"一").start();
7         new Thread(runnableImplsyn,"二").start();
8     }
9 }

四,問題解決方案之靜態synchronize方法:

同上

 1 public class RunnableImplsynfn implements Runnable {
 2 
 3 private static int ticket=200;
 4     @Override
 5     public void run() {
 6         statictest();
 7 
 8     }
 9 
10     private static synchronized void statictest() {
11         while(true){
12             if (ticket<=0){
13                 break;
14             }
15             try {
16                 Thread.sleep(200);
17                 String name = Thread.currentThread().getName();
18                 System.out.println("第"+name+"窗口正在賣出第"+(200-ticket+1)+"張票,剩余"+(--ticket)+"張");
19             } catch (InterruptedException e) {
20                 e.printStackTrace();
21             }
22 
23         }
24 
25     }
26    
27 
28     }
29     }

測試類一樣略。

五,問題解決方案之lock方法:

 1 import java.util.concurrent.locks.Lock;
 2 import java.util.concurrent.locks.ReentrantLock;
 3 
 4 public class Runnablelock implements Runnable {
 5     private int ticket=200;
 6    Lock l= new ReentrantLock();
 7 
 8     @Override
 9     public void run() {
10         while(true){
11  /*       try {
12         Thread.sleep(20);
13         } catch (InterruptedException e) {
14             e.printStackTrace();
15         }*/
16 l.lock();//從此以后加鎖
17 
18             if (ticket<=0){
19                 break;
20             }
21             try {
22                 Thread.sleep(200);
23 
24                 String name = Thread.currentThread().getName();
25                 System.out.println("第"+name+"窗口正在賣出第"+(200-ticket+1)+"張票,剩余"+(--ticket)+"張");
26             } catch (InterruptedException e) {
27                 e.printStackTrace();
28             }finally {
29                 l.unlock();//釋放鎖
30             }
31 
32         }
33 
34 
35     }
36 }

測試類:

1 public class lockTicket {
2 
3 
4     public static void main(String[] args) {
5         Runnablelock runnablelock = new Runnablelock();
6         new Thread(runnablelock,"一").start();
7         new Thread(runnablelock,"二").start();
8     }
9 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM