Java高并发编程:多个线程之间共享数据的方式探讨
內(nèi)容摘要
多個(gè)線程之間共享數(shù)據(jù),按照每個(gè)線程執(zhí)行代碼是否相同,我們可以采取不同的處理方式,這里通過(guò)簡(jiǎn)單的賣(mài)票示例說(shuō)明了當(dāng)每個(gè)線程執(zhí)行相同代碼的情況,對(duì)于多個(gè)線程執(zhí)行不同代碼的情況,處理方式比較靈活,這里主要介紹了2種方式,通過(guò)2種方式的對(duì)比和歸納,我們可以總結(jié)出在多個(gè)線程執(zhí)行不同的代碼情況下,如何進(jìn)行代碼的設(shè)計(jì)
1. 如果每個(gè)線程執(zhí)行的代碼相同
可以使用同一個(gè)Runnable對(duì)象,這個(gè)Runnable對(duì)象中有那個(gè)共享數(shù)據(jù),例如:賣(mài)票系統(tǒng)
1.1 簡(jiǎn)單的賣(mài)票系統(tǒng)示例
class Ticket implements Runnable{ private int tick = 20; Object obj = new Object(); public void run(){ while(true){ synchronized(obj){ if(tick>0){ //只能try,因?yàn)閞un是復(fù)寫(xiě)了Runnable接口的run,接口的run沒(méi)有拋 //try{Thread.sleep(10);}catch(Exception e){} System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--); } } } } } class TicketDemo { public static void main(String[] args) { //只建立了一個(gè)Ticket對(duì)象,內(nèi)存中只有一個(gè)tick成員變量,所以是共享數(shù)據(jù) Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); Thread t3 = new Thread(t); Thread t4 = new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); } } Thread-0....sale : 20 Thread-0....sale : 19 Thread-0....sale : 18 Thread-0....sale : 17 Thread-0....sale : 16 Thread-0....sale : 15 Thread-0....sale : 14 Thread-0....sale : 13 Thread-0....sale : 12 Thread-3....sale : 11 Thread-3....sale : 10 Thread-3....sale : 9 Thread-3....sale : 8 Thread-3....sale : 7 Thread-3....sale : 6 Thread-3....sale : 5 Thread-3....sale : 4 Thread-3....sale : 3 Thread-3....sale : 2 Thread-3....sale : 12. 如果每個(gè)線程執(zhí)行的代碼不同
這時(shí)候不需要用不同的Runnable對(duì)象,有如下兩種方式來(lái)實(shí)現(xiàn)這些Runnable對(duì)象之間的數(shù)據(jù)共享。
2.1 方式1
將共享數(shù)據(jù)封裝在另外一個(gè)對(duì)象中,然后將這個(gè)對(duì)象逐一傳遞給各個(gè)Runnable對(duì)象。每個(gè)線程對(duì)共享數(shù)據(jù)的操作方法也分配到那個(gè)對(duì)象身上去完成,這樣容易實(shí)現(xiàn)針對(duì)該數(shù)據(jù)進(jìn)行的各個(gè)操作的互斥和通信。
思想:一個(gè)類(lèi)提供數(shù)據(jù)和操作數(shù)據(jù)的同步方法,另外定義兩個(gè)線程通過(guò)構(gòu)造函數(shù)接收并操作數(shù)據(jù),在主函數(shù)中直接創(chuàng)建線程對(duì)象,即可完成操作
2.2 方式2
將這些Runnable對(duì)象作為某一個(gè)類(lèi)中的內(nèi)部類(lèi),共享數(shù)據(jù)作為這個(gè)外部類(lèi)中的成員變量,每個(gè)線程對(duì)共享數(shù)據(jù)的操作方式也分配給外部類(lèi),以便實(shí)現(xiàn)對(duì)共享數(shù)據(jù)進(jìn)行的各個(gè)操作的互斥和通信,作為內(nèi)部類(lèi)的各個(gè)Runnable對(duì)象調(diào)用外部類(lèi)的這些方法。
思想:一個(gè)外部類(lèi)里面有兩個(gè)內(nèi)部類(lèi),為了讓這兩個(gè)內(nèi)部類(lèi)共享數(shù)據(jù),讓它們都操作外部類(lèi)的同一個(gè)成員,方法和數(shù)據(jù)都在這個(gè)成員身上,直接
調(diào)用方法即可完成 數(shù)據(jù)的操作
2.3 方式3:將上面兩種方式的組合
將共享數(shù)據(jù)封裝在另外一個(gè)對(duì)象中,每個(gè)線程對(duì)共享數(shù)據(jù)的操作方法也分配到那個(gè)對(duì)象身上去完成,對(duì)象作為這個(gè)外部類(lèi)中的成員變量或方法中的局部變量,每個(gè)線程的Runnable的對(duì)象作為外部類(lèi)中的成員內(nèi)部類(lèi)或局部外部類(lèi)。
2.4 技巧總結(jié)
要同步互斥的幾段代碼最好是分別放在幾個(gè)獨(dú)立的方法中,這些方法再放在同一個(gè)類(lèi)中,這樣比較容易實(shí)現(xiàn)它們之間的同步互斥或通信。
2.5 對(duì)于每個(gè)線程執(zhí)行的代碼不同下的3種方式,通過(guò)一個(gè)面試題來(lái)說(shuō)明
需求:設(shè)計(jì)4個(gè)線程,其中兩個(gè)線程每次對(duì)j增加1,另外兩個(gè)線程每次對(duì)j減少1,,寫(xiě)出程序
使用方式1實(shí)現(xiàn)
將數(shù)據(jù)和操作共享數(shù)據(jù)的方法封裝在一個(gè)類(lèi)中定義兩個(gè)runnable實(shí)現(xiàn)類(lèi),讓兩個(gè)runnable都持有共享數(shù)據(jù)的引用,在runnable的構(gòu)造函數(shù)中,直接傳入去操作,在實(shí)現(xiàn)類(lèi)的run方法中調(diào)用封裝類(lèi)的方法
public class MultyThreadShareMethod1 { public static void main(String[] args){ //將數(shù)據(jù)封裝到一個(gè)對(duì)象上, ShareData2 data1 = new ShareData2(); //在runnable的構(gòu)造函數(shù)中直接傳入去操作 for(int i=0;i<2;i++){ new Thread(new MyRunnable1(data1)).start(); new Thread(new MyRunnable2(data1)).start(); } } } //封裝共享數(shù)據(jù)和操作共享數(shù)據(jù)方法的類(lèi) class ShareData2{ private int j = 10; public synchronized void increment() { j++; System.out.println(Thread.currentThread().getName()+" inc : "+j); } public synchronized void decrement() { j--; System.out.println(Thread.currentThread().getName()+" dec : "+j); } } //增加的線程,需要傳入一個(gè)共享數(shù)據(jù) class MyRunnable1 implements Runnable { private ShareData2 data; public MyRunnable1(ShareData2 data) { this.data = data; } @Override public void run() { for(int i=0;i<10;i++){ data.increment(); } } } //減少的線程,需要傳入一個(gè)共享數(shù)據(jù) class MyRunnable2 implements Runnable { private ShareData2 data; public MyRunnable2(ShareData2 data) { this.data = data; } @Override public void run() { for(int i=0;i<10;i++){ data.decrement(); } } }輸出結(jié)果
Thread-0 inc : 11 Thread-0 inc : 12 Thread-0 inc : 13 Thread-0 inc : 14 Thread-0 inc : 15 Thread-0 inc : 16 Thread-0 inc : 17 Thread-0 inc : 18 Thread-0 inc : 19 Thread-0 inc : 20 Thread-1 dec : 19 Thread-3 dec : 18 Thread-3 dec : 17 Thread-3 dec : 16 Thread-3 dec : 15 Thread-3 dec : 14 Thread-3 dec : 13 Thread-3 dec : 12 Thread-3 dec : 11 Thread-3 dec : 10 Thread-3 dec : 9 Thread-2 inc : 10 Thread-2 inc : 11 Thread-1 dec : 10 Thread-1 dec : 9 Thread-1 dec : 8 Thread-1 dec : 7 Thread-1 dec : 6 Thread-1 dec : 5 Thread-1 dec : 4 Thread-1 dec : 3 Thread-1 dec : 2 Thread-2 inc : 3 Thread-2 inc : 4 Thread-2 inc : 5 Thread-2 inc : 6 Thread-2 inc : 7 Thread-2 inc : 8 Thread-2 inc : 9 Thread-2 inc : 10使用方式2實(shí)現(xiàn)
將數(shù)據(jù)和操作共享數(shù)據(jù)的方法封裝在一個(gè)類(lèi)中
兩個(gè)runnable作為它的內(nèi)部類(lèi),相對(duì)于方式1,這里沒(méi)有將數(shù)據(jù)傳給runnable,而是讓它們自己去取,在自己的run方法中調(diào)用操作數(shù)據(jù)的方法
這里的共享變量可以定義為靜態(tài)類(lèi)型的成員變量,也可以定義為final類(lèi)型的局部變量。
public class MultyThreadShareData { //共享數(shù)據(jù)作為外部類(lèi)的成員變量 //private static ShareData data = new ShareData(); public static void main(String[] args){ //也可以定義為final類(lèi)型的局部變量 final ShareData data = new ShareData(); //開(kāi)啟4條線程 for(int i=0;i<2;i++){ //增加的線程 new Thread(new Runnable(){ @Override public void run() { for(int i=0;i<100;i++){ data.increment(); } } }).start(); //減少的線程 new Thread(new Runnable(){ @Override public void run() { for(int i=0;i<100;i++){ data.decrement(); } } }).start(); } } } //封裝共享數(shù)據(jù)和操作共享數(shù)據(jù)方法的類(lèi) class ShareData{ private int j = 0; public synchronized void increment() { j++; System.out.println(Thread.currentThread().getName()+" inc : "+j); } public synchronized void decrement() { j--; System.out.println(Thread.currentThread().getName()+" dec : "+j); } }兩種方式的組合實(shí)現(xiàn)
public class MultyThreadShareDataTest { private int j; public static void main(String args[]){ MultyThreadShareDataTest tt=new MultyThreadShareDataTest(); Inc inc=tt.new Inc(); Dec dec=tt.new Dec(); for(int i=0;i<2;i++){ Thread t=new Thread(inc); t.start(); t=new Thread(dec); t.start(); } } private synchronized void inc(){ j++; System.out.println(Thread.currentThread().getName()+"-inc:"+j); } private synchronized void dec(){ j--; System.out.println(Thread.currentThread().getName()+"-dec:"+j); } class Inc implements Runnable{ public void run(){ for(int i=0;i<100;i++){ inc(); } } } class Dec implements Runnable{ public void run(){ for(int i=0;i<100;i++){ dec(); } } } }總結(jié)
以上是生活随笔為你收集整理的Java高并发编程:多个线程之间共享数据的方式探讨的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Eclipse Memory Analy
- 下一篇: Java高并发编程:同步工具类