標籤:nts 適合 system 問題: hex 兩種 static 獨立 覆寫
在java中可有兩種方式實現多線程,一種是繼承Thread類,一種是實現Runnable介面;Thread類是在java.lang包中定義的。一個類只要繼承了Thread類同時覆寫了本類中的run()方法就可以實現多線程操作了,但是一個類只能繼承一個父類,這是此方法的局限。
1 public class Actor extends Thread {2 public void run(){3 //線程執行的操作4 }5 }
在實際開發中一個多線程的操作很少使用Thread類,而是通過Runnable介面完成。
1 public class Actress implements Runnable{2 3 @Override4 public void run() {5 //線程執行的操作6 }7 }
在主方法中調用這兩種線程。
1 public static void main(String[] args) {2 Thread actor=new Actor();3 actor.setName("Mr.thread"); //Thread 線程4 actor.start();5 6 Thread actressThread=new Thread(new Actress(),"Miss.Runnable"); //Runnable 線程7 actressThread.start();8 }
兩種實現方式的區別和聯絡:
在程式開發中只要是多線程肯定永遠以實現Runnable介面為主,因為實現Runnable介面相比繼承Thread類有如下好處:
1、避免點繼承的局限,一個類可以繼承多個介面。
2、適合於資源的共用
以賣票程式為例,通過Thread類完成:
1 package multithreading; 2 3 public class MyThreadWithExtends extends Thread { 4 5 private int tickets = 10; 6 7 @Override 8 public void run() { 9 10 for (int i = 0; i <= 100; i++) {11 if(tickets>0){12 System.out.println(Thread.currentThread().getName()+"--賣出票:" + tickets--);13 }14 }15 }16 17 18 public static void main(String[] args) {19 MyThreadWithExtends thread1 = new MyThreadWithExtends();20 MyThreadWithExtends thread2 = new MyThreadWithExtends();21 MyThreadWithExtends thread3 = new MyThreadWithExtends();22 23 thread1.start();24 thread2.start();25 thread3.start();26 27 //每個線程都獨立,不共用資源,每個線程都賣出了10張票,總共賣出了30張。如果真賣票,就有問題了。28 }29 30 }
運行結果:
Thread-0--賣出票:10
Thread-2--賣出票:10
Thread-1--賣出票:10
Thread-2--賣出票:9
Thread-0--賣出票:9
Thread-2--賣出票:8
Thread-1--賣出票:9
Thread-2--賣出票:7
Thread-0--賣出票:8
Thread-2--賣出票:6
Thread-2--賣出票:5
Thread-2--賣出票:4
Thread-1--賣出票:8
Thread-2--賣出票:3
Thread-0--賣出票:7
Thread-2--賣出票:2
Thread-2--賣出票:1
Thread-1--賣出票:7
Thread-0--賣出票:6
Thread-1--賣出票:6
Thread-0--賣出票:5
Thread-0--賣出票:4
Thread-1--賣出票:5
Thread-0--賣出票:3
Thread-1--賣出票:4
Thread-1--賣出票:3
Thread-1--賣出票:2
Thread-0--賣出票:2
Thread-1--賣出票:1
Thread-0--賣出票:1
如果用Runnable就可以實現資源共用,下面看例子:
1 package multithreading; 2 3 public class MyThreadWithImplements implements Runnable { 4 5 private int tickets = 10; 6 7 @Override 8 public void run() { 9 10 for (int i = 0; i <= 100; i++) {11 if(tickets>0){12 System.out.println(Thread.currentThread().getName()+"--賣出票:" + tickets--);13 }14 }15 }16 17 18 public static void main(String[] args) {19 MyThreadWithImplements myRunnable = new MyThreadWithImplements();20 Thread thread1 = new Thread(myRunnable, "視窗一");21 Thread thread2 = new Thread(myRunnable, "視窗二");22 Thread thread3 = new Thread(myRunnable, "視窗三");23 24 thread1.start();25 thread2.start();26 thread3.start();27 }28 29 }
運行結果:
視窗二--賣出票:10
視窗三--賣出票:9
視窗一--賣出票:8
視窗三--賣出票:6
視窗三--賣出票:4
視窗三--賣出票:3
視窗三--賣出票:2
視窗三--賣出票:1
視窗二--賣出票:7
視窗一--賣出票:5
每個線程共用了對象myRunnable的資源,賣出的總票數是對的,但是順序是亂的,怎麼辦?
同步關鍵詞synchronized
線程執行的時候,一個個執行不就有序了。即線程1在執行的時候,其他線程阻塞不要執行。
加synchronize。
1 package multithreading.sync; 2 3 public class MyThreadWithImplements implements Runnable { 4 5 private int tickets = 10; 6 7 @Override 8 public synchronized void run() { 9 //同步關鍵詞synchronized10 for (int i = 0; i <= 100; i++) {11 if(tickets>0){12 System.out.println(Thread.currentThread().getName()+"--賣出票:" + tickets--);13 }14 }15 }16 17 18 public static void main(String[] args) {19 20 MyThreadWithImplements myRunnable = new MyThreadWithImplements();21 Thread thread1 = new Thread(myRunnable, "視窗一");22 Thread thread2 = new Thread(myRunnable, "視窗二");23 Thread thread3 = new Thread(myRunnable, "視窗三");24 25 thread1.start();26 thread2.start();27 thread3.start();28 }29 30 }
運行結果
視窗一--賣出票:10
視窗一--賣出票:9
視窗一--賣出票:8
視窗一--賣出票:7
視窗一--賣出票:6
視窗一--賣出票:5
視窗一--賣出票:4
視窗一--賣出票:3
視窗一--賣出票:2
視窗一--賣出票:1
缺陷
1、如果這個擷取鎖的線程由於要等待IO或者其他原因(比如調用sleep方法)被阻塞了,但是又沒有釋放鎖,其他線程便只能乾巴巴地等待,這多麼影響程式執行效率。
2、當有多個線程讀寫檔案時,讀寫操作會發生衝突現象,寫操作會發生衝突現象,但是讀操作不會發生衝突現象。但是採用synchronized關鍵字來實現同步的話,就會導致一個問題:如果多個線程都只是進行讀操作,當一個線程在進行讀操作時,其他線程只能等待無法進行讀操作。
因此就需要一種機制來使得多個線程都只是進行讀操作時,線程之間不會發生衝突,通過Lock就可以辦到。另外,通過Lock可以知道線程有沒有成功擷取到鎖。這個是synchronized無法辦到的。總的來說,也就是說Lock提供了比synchronized更多的功能。
ReadWriteLock讀寫檔案概述
ReadWriteLock是一個介面,在它裡面只定義了兩個方法:一個讀的鎖和一個寫的鎖。
讀的鎖:A線程擷取了讀的鎖,那麼B線程也可以擷取讀的鎖。
寫的鎖:A線程擷取了寫的鎖,那麼B線程不能擷取讀也不能擷取寫的鎖。
1 public interface ReadWriteLock { 2 /** 3 * Returns the lock used for reading. 4 * 讀的鎖,A線程擷取了讀的鎖,那麼B線程也可以擷取讀的鎖 5 * @return the lock used for reading. 6 */ 7 Lock readLock(); 8 9 /** 10 * Returns the lock used for writing. 11 * 寫的鎖,A線程擷取了寫的鎖,那麼B線程不能擷取讀也不能擷取寫的鎖。 12 * @return the lock used for writing. 13 */ 14 Lock writeLock(); 15 }
。。。未完待續
JAVA多線程 & 同步關鍵詞synchronized & ReadWriteLock讀寫檔案