導航:首頁 > 解決方法 > 多線程代碼解決方法

多線程代碼解決方法

發布時間:2022-06-10 19:08:53

1. 多線程有幾種實現方法

在java5以前實現多線程有兩種方法(繼承Thread類和實現Runnable介面)
它們分別為:
使用new Thread()和new Thread(Runnable)形式
第一種直接調用thread的run方法,所以,往往使用Thread子類,即new SubThread()。
第二種調用
Runnable的run方法。
第一種:
new Thread(){}.start();這表示調用Thread子類對象的run方法,new Thread(){}表示一個Thread的匿名子類的實例對象,子類加上run方法後的代碼如下:
new Thread(){
public void run(){
}
}.start();
第二種:
new Thread(
new Runnable(){}
).start();
這表示調用Thread對象接受的Runnable對象的run方法,new Runnable(){}表示一個Runnable的匿名子類的實例對象,
runnable的子類加上run方法後的代碼如下:
new Thread(new Runnable(){
public void run(){
}
}
).start();

2. 如何解決java 多線程問題

Java線程同步需要我們不斷的進行相關知識的學習,下面我們就來看看如何才能更好的在學習中掌握相關的知識訊息,來完善我們自身的編寫手段。希望大家有所收獲。 Java線程同步的優先順序代表該線程的重要程度,當有多個線程同時處於可執行狀態並等待獲得 CPU 時間時,線程調度系統根據各個線程的優先順序來決定給誰分配 CPU 時間,優先順序高的線程有更大的機會獲得 CPU 時間,優先順序低的線程也不是沒有機會,只是機會要小一些罷了。 你可以調用 Thread 類的方法 getPriority()和 setPriority()來存取Java線程同步的優先順序,線程的優先順序界於1(MIN_PRIORITY)和10(MAX_PRIORITY)之間,預設是5(NORM_PRIORITY)。 Java線程同步 由於同一進程的多個線程共享同一片存儲空間,在帶來方便的同時,也帶來了訪問沖突這個嚴重的問題。Java語言提供了專門機制以解決這種沖突,有效避免了同一個數據對象被多個線程同時訪問。 由於我們可以通過 private 關鍵字來保證數據對象只能被方法訪問,所以我們只需針對方法提出一套機制,這套機制就是 synchronized 關鍵字,它包括兩種用法:synchronized 方法和 synchronized 塊。 1. synchronized 方法:通過在方法聲明中加入 synchronized關鍵字來聲明 synchronized 方法。如:1. public synchronized void accessVal(int newVal); synchronized 方法控制對類成員變數的訪問:每個類實例對應一把鎖,每個 synchronized 方法都必須獲得調用該方法的類實例的鎖方能執行,否則所屬線程阻塞,方法一旦執行,就獨占該鎖,直到從該方法返回時才將鎖釋放,此後被阻塞的Java線程同步方能獲得該鎖,重新進入可執行狀態。 這種機制確保了同一時刻對於每一個類實例,其所有聲明為 synchronized 的成員函數中至多隻有一個處於可執行狀態(因為至多隻有一個能夠獲得該類實例對應的鎖),從而有效避免了類成員變數的訪問沖突(只要所有可能訪問類成員變數的方法均被聲明為 synchronized)。 在 Java 中,不光是類實例,每一個類也對應一把鎖,這樣我們也可將類的靜態成員函數聲明為 synchronized ,以控制其對類的靜態成員變數的訪問。 synchronized 方法的缺陷:若將一個大的方法聲明為synchronized 將會大大影響效率,典型地,若將線程類的方法 run()聲明為 synchronized ,由於在線程的整個生命期內它一直在運行,因此將導致它對本類任何 synchronized 方法的調用都永遠不會成功。當然我們可以通過將訪問類成員變數的代碼放到專門的方法中,將其聲明為 synchronized ,並在主方法中調用來解決這一問題,但是 Java 為我們提供了更好的解決辦法,那就是 synchronized 塊。 2. synchronized 塊:通過 synchronized關鍵字來聲明synchronized 塊。語法如下:1. synchronized(syncObject)2. {3. //允許訪問控制的代碼4. } synchronized 塊是這樣一個代碼塊,其中的代碼必須獲得對象 syncObject (如前所述,可以是類實例或類)的鎖方能執行,具體機制同前所述。由於可以針對任意代碼塊,且可任意指定上鎖的對象,故靈活性較高。 Java線程同步的阻塞 為了解決對共享存儲區的訪問沖突,Java 引入了同步機制,現在讓我們來考察多個Java線程同步對共享資源的訪問,顯然同步機制已經不夠了,因為在任意時刻所要求的資源不一定已經准備好了被訪問,反過來,同一時刻准備好了的資源也可能不止一個。為了解決這種情況下的訪問控制問題,Java 引入了對阻塞機制的支持。 阻塞指的是暫停一個Java線程同步的執行以等待某個條件發生(如某資源就緒),學過操作系統的同學對它一定已經很熟悉了。Java 提供了大量方法來支持阻塞,下面讓我們逐一分析。

3. Java多線程方案如何處理關鍵代碼

  1. public<T>voidParallelRecursive(finalExecutorexec,List<Node<T>>nodes,Collection<T>results){

  2. for(Node<T>n:nodes){

  3. exec.execute(newRunnable(){

  4. publicvoidrun(){

  5. results.add(n.compute());

  6. }

  7. });

  8. parallelRecursive(exec,n.getChildren(),results);

  9. }

  10. }

  11. public<T>Collection<T>getParallelResults(List<Node<T>>nodes)

  12. throwsInterruptedException{

  13. ExecutorServiceexec=Executors.newCachedThreadPool();

  14. Queue<T>resultQueue=newConcurrentLinkedQueue<T>();

  15. parallelRecursive(exec,nodes,resultQueue);

  16. exec.shutdown();

  17. exec.awaitTermination(Long.MAX_VALUE,TimeUnit.SECONDS);

  18. returnreslutQueue;

  19. }

4. 在Java 中多線程的實現方法有哪些,如何使用

Java多線程的創建及啟動

Java中線程的創建常見有如三種基本形式

1.繼承Thread類,重寫該類的run()方法。

復制代碼

1 class MyThread extends Thread {

2

3 private int i = 0;

4

5 @Override

6 public void run() {

7 for (i = 0; i < 100; i++) {

8 System.out.println(Thread.currentThread().getName() + " " + i);

9 }

10 }

11 }

復制代碼

復制代碼

1 public class ThreadTest {

2

3 public static void main(String[] args) {

4 for (int i = 0; i < 100; i++) {

5 System.out.println(Thread.currentThread().getName() + " " + i);

6 if (i == 30) {

7 Thread myThread1 = new MyThread(); // 創建一個新的線程 myThread1 此線程進入新建狀態

8 Thread myThread2 = new MyThread(); // 創建一個新的線程 myThread2 此線程進入新建狀態

9 myThread1.start(); // 調用start()方法使得線程進入就緒狀態

10 myThread2.start(); // 調用start()方法使得線程進入就緒狀態

11 }

12 }

13 }

14 }

復制代碼

如上所示,繼承Thread類,通過重寫run()方法定義了一個新的線程類MyThread,其中run()方法的方法體代表了線程需要完成的任務,稱之為線程執行體。當創建此線程類對象時一個新的線程得以創建,並進入到線程新建狀態。通過調用線程對象引用的start()方法,使得該線程進入到就緒狀態,此時此線程並不一定會馬上得以執行,這取決於CPU調度時機。

2.實現Runnable介面,並重寫該介面的run()方法,該run()方法同樣是線程執行體,創建Runnable實現類的實例,並以此實例作為Thread類的target來創建Thread對象,該Thread對象才是真正的線程對象。

復制代碼

1 class MyRunnable implements Runnable {

2 private int i = 0;

3

4 @Override

5 public void run() {

6 for (i = 0; i < 100; i++) {

7 System.out.println(Thread.currentThread().getName() + " " + i);

8 }

9 }

10 }

復制代碼

復制代碼

1 public class ThreadTest {

2

3 public static void main(String[] args) {

4 for (int i = 0; i < 100; i++) {

5 System.out.println(Thread.currentThread().getName() + " " + i);

6 if (i == 30) {

7 Runnable myRunnable = new MyRunnable(); // 創建一個Runnable實現類的對象

8 Thread thread1 = new Thread(myRunnable); // 將myRunnable作為Thread target創建新的線程

9 Thread thread2 = new Thread(myRunnable);

10 thread1.start(); // 調用start()方法使得線程進入就緒狀態

11 thread2.start();

12 }

13 }

14 }

15 }

復制代碼

相信以上兩種創建新線程的方式大家都很熟悉了,那麼Thread和Runnable之間到底是什麼關系呢?我們首先來看一下下面這個例子。

復制代碼

1 public class ThreadTest {

2

3 public static void main(String[] args) {

4 for (int i = 0; i < 100; i++) {

5 System.out.println(Thread.currentThread().getName() + " " + i);

6 if (i == 30) {

7 Runnable myRunnable = new MyRunnable();

8 Thread thread = new MyThread(myRunnable);

9 thread.start();

10 }

11 }

12 }

13 }

14

15 class MyRunnable implements Runnable {

16 private int i = 0;

17

18 @Override

19 public void run() {

20 System.out.println("in MyRunnable run");

21 for (i = 0; i < 100; i++) {

22 System.out.println(Thread.currentThread().getName() + " " + i);

23 }

24 }

25 }

26

27 class MyThread extends Thread {

28

29 private int i = 0;

30

31 public MyThread(Runnable runnable){

32 super(runnable);

33 }

34

35 @Override

36 public void run() {

37 System.out.println("in MyThread run");

38 for (i = 0; i < 100; i++) {

39 System.out.println(Thread.currentThread().getName() + " " + i);

40 }

41 }

42 }

復制代碼

同樣的,與實現Runnable介面創建線程方式相似,不同的地方在於

1 Thread thread = new MyThread(myRunnable);

那麼這種方式可以順利創建出一個新的線程么?答案是肯定的。至於此時的線程執行體到底是MyRunnable介面中的run()方法還是MyThread類中的run()方法呢?通過輸出我們知道線程執行體是MyThread類中的run()方法。其實原因很簡單,因為Thread類本身也是實現了Runnable介面,而run()方法最先是在Runnable介面中定義的方法。

1 public interface Runnable {

2

3 public abstract void run();

4

5 }

我們看一下Thread類中對Runnable介面中run()方法的實現:

復制代碼

@Override

public void run() {

if (target != null) {

target.run();

}

}

復制代碼

也就是說,當執行到Thread類中的run()方法時,會首先判斷target是否存在,存在則執行target中的run()方法,也就是實現了Runnable介面並重寫了run()方法的類中的run()方法。但是上述給到的列子中,由於多態的存在,根本就沒有執行到Thread類中的run()方法,而是直接先執行了運行時類型即MyThread類中的run()方法。

3.使用Callable和Future介面創建線程。具體是創建Callable介面的實現類,並實現clall()方法。並使用FutureTask類來包裝Callable實現類的對象,且以此FutureTask對象作為Thread對象的target來創建線程。

看著好像有點復雜,直接來看一個例子就清晰了。

復制代碼

1 public class ThreadTest {

2

3 public static void main(String[] args) {

4

5 Callable<Integer> myCallable = new MyCallable(); // 創建MyCallable對象

6 FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask來包裝MyCallable對象

7

8 for (int i = 0; i < 100; i++) {

9 System.out.println(Thread.currentThread().getName() + " " + i);

10 if (i == 30) {

11 Thread thread = new Thread(ft); //FutureTask對象作為Thread對象的target創建新的線程

12 thread.start(); //線程進入到就緒狀態

13 }

14 }

15

16 System.out.println("主線程for循環執行完畢..");

17

18 try {

19 int sum = ft.get(); //取得新創建的新線程中的call()方法返回的結果

20 System.out.println("sum = " + sum);

21 } catch (InterruptedException e) {

22 e.printStackTrace();

23 } catch (ExecutionException e) {

24 e.printStackTrace();

25 }

26

27 }

28 }

29

30

31 class MyCallable implements Callable<Integer> {

32 private int i = 0;

33

34 // 與run()方法不同的是,call()方法具有返回值

35 @Override

36 public Integer call() {

37 int sum = 0;

38 for (; i < 100; i++) {

39 System.out.println(Thread.currentThread().getName() + " " + i);

40 sum += i;

41 }

42 return sum;

43 }

44

45 }

復制代碼

首先,我們發現,在實現Callable介面中,此時不再是run()方法了,而是call()方法,此call()方法作為線程執行體,同時還具有返回值!在創建新的線程時,是通過FutureTask來包裝MyCallable對象,同時作為了Thread對象的target。那麼看下FutureTask類的定義:

1 public class FutureTask<V> implements RunnableFuture<V> {

2

3 //....

4

5 }

1 public interface RunnableFuture<V> extends Runnable, Future<V> {

2

3 void run();

4

5 }

於是,我們發現FutureTask類實際上是同時實現了Runnable和Future介面,由此才使得其具有Future和Runnable雙重特性。通過Runnable特性,可以作為Thread對象的target,而Future特性,使得其可以取得新創建線程中的call()方法的返回值。

執行下此程序,我們發現sum = 4950永遠都是最後輸出的。而「主線程for循環執行完畢..」則很可能是在子線程循環中間輸出。由CPU的線程調度機制,我們知道,「主線程for循環執行完畢..」的輸出時機是沒有任何問題的,那麼為什麼sum =4950會永遠最後輸出呢?

原因在於通過ft.get()方法獲取子線程call()方法的返回值時,當子線程此方法還未執行完畢,ft.get()方法會一直阻塞,直到call()方法執行完畢才能取到返回值。

上述主要講解了三種常見的線程創建方式,對於線程的啟動而言,都是調用線程對象的start()方法,需要特別注意的是:不能對同一線程對象兩次調用start()方法。

你好,本題已解答,如果滿意

請點右下角「採納答案」。


5. java多線程有幾種實現方法

6. 多線程有幾種實現方法,都是什麼同步有幾種實現方法,都是什麼

java中多線程的實現方法有兩種:1.直接繼承thread類;2.實現runnable介面;同步的實現方法有五種:1.同步方法;2.同步代碼塊;3.使用特殊域變數(volatile)實現線程同步;4.使用重入鎖實現線程同步;5.使用局部變數實現線程同步 。
其中多線程實現過程中需注意重寫或者覆蓋run()方法,而對於同步的實現方法中使用較常使用的是利用synchronized編寫同步方法和代碼塊。

7. 實現多線程都有哪幾種方法

1:UI線程。這個線程是操作系統自動創建的,你畫了個winform,那麼程序一啟動,自然有了這么個線程。值得注意的是,你添加一個Timer控制項,現實的多線程,實際上,依然在UI線程里。只是定時被Timer奪去控制權而已,本質上依然是單線程。另一個線索也可以論證:本來非UI線程想更新UI界面,是需要利用delegate,involk等來實現的,但是在timer控制項的線程里,是不需要的。2:Threadthread=newThread(obj.functionName);thread.start();這樣自定義的線程是真正的多線程,它的使用也是最靈活的。不像Timer線程,精確度只有50ms。值得注意的是:如果需要啟動的線程函數是帶輸入參數的,怎麼?有兩個法:A:你不是啟動obj對象里的函數嗎?在thread.start();之前,你先添加這句話MyObjectobj=newMyObject(inta,intb);這樣,obj.functionName函數里可以直接使用a和b了。還有個方法,就是利用委託封裝函數,然後thread.start(參數);具體代碼如下:[ComVisibleAttribute(false)](Objectobj)//這個Thread類的構造方法的定義如下:publicThread(ParameterizedThreadStartstart);(Objectobj){Console.WriteLine(obj);}staticvoidMain(string[]args){Threadthread=newThread(myStaticParamThreadMethod);thread.Start("通過委託的參數傳值");}3:利用threadpool線程池技術。threadpool的主要原理是池裡面的線程不會完成一個任務就消亡,而是會繼續執行其他的任務,這減少了線程的消亡和生成的代價。主要是ThreadPool.QueueUserWorkItem()和ThreadPool.RegisterWaitForSingleObject(···)兩個靜態函數。具體如下:QueueUserWorkItem的使用:staticvoidThreadProc(ObjectstateInfo){Console.WriteLine("Hellofromthethreadpool.");}Main函數里ThreadPool.QueueUserWorkItem(newWaitCallback(ThreadProc));即可。(注意WaitCallback系統委託),它的功能就像第2種方法里提到的newthread。那麼RegisterWaitForSingleObject是干什麼的呢?這個方法的做用是向線程池添加一個可以定時執行的方法。有點像第一種方法里提到的timer線程,卻不屬於UI線程。具體的使用如下:AutoResetEventwait=newAutoResetEvent(false);objectstate=newobject();ThreadPool.RegisterWaitForSingleObject(wait,newWaitOrTimerCallback(test),state,5000,false);//5000是間隔調用的時間,也就是wait變數卡住的timeout時間(我覺得內部是這樣實現的)wait.Set();//如果有set這句話,那麼第一次執行不用等5秒,則直接執行目標函數,否則沒這句話,第一次執行要等5秒的。還有一個要注意:我平常使用的是ManualResetEvent,但在threadpool里,首先要選的是AutoResetEvent,因為AutoResetEvent能自動reset,所以下一次間隔來了,又要重新等待5秒鍾,達到定時器的目的。如果是ManualResetEvent,要麼一次執行不了(初始值為false),要麼不間斷的玩命執行。ManualResetEvent和AutoResetEvent的另一個重要區別是前者能一次喚醒多個線程,而後者一次只能喚醒一個線程。其實RegisterWaitForSingleObject函數的使用有點想我封裝好的MyTimer類的實現了:我裡面的while死循環里用了個wait.waitone(2000,false);即可。對了,說到這里,RegisterWaitForSingleObject函數實現的定時器,如果手動停止呢?這要用到Unregister函數:RegisteredWaitHandlerw=ThreadPool.RegisterWaitForSingleObject(wait,newWaitOrTimerCallback(test),state,3000,false);rw.Unregister(wait);嗯討論了這么多線程的東西,乾脆再說一個小點:Thread.IsBackground=true的時候,指示該線程為後台線程。後台線程將會隨著主線程的退出而退出

8. 解決多線程安全問題,代碼方面怎麼優化

有2種解決方法
第一,是採用原子變數,畢竟線程安全問題最根本上是由於全局變數和靜態變數引起的,只要保證了對於變數的寫操作要麼全寫要麼不寫,就可以解決線程安全,定義變數用sig_atomic_t和volatile。
第二,就是實現線程間同步啦,用互斥索,信號量。讓線程有序的訪問變數就可以啦

9. java電商項目面試官問我高並發多線程怎麼解決

這個很簡單,高並發有多種解決方法:

1、從代碼上分入手,必須得保證代碼沒有冗餘,不要有廢代碼;
2、從伺服器上入手,高並發一台伺服器並發量有限,我們可以採用多台伺服器來分擔壓力;
3、從存儲方便入手,像我們一般高並發但是數據卻可以不用存到資料庫中的,我們就存在內存中,因為讀內存的速度是資料庫的N倍。

10. java多線程解決同步問題的幾種方式,原理和代碼

在Java中一共有四種方法支持同步,其中前三個是同步方法,一個是管道方法。管道方法不建議使用。

閱讀全文

與多線程代碼解決方法相關的資料

熱點內容
大蒜治療金魚腸炎土方法怎麼治療 瀏覽:769
江蘇高質量考核發展指數計算方法 瀏覽:917
蟲牙土方法怎麼治 瀏覽:291
水膠體敷料使用方法 瀏覽:828
粉絲的訓練方法 瀏覽:778
鋁蓋發霉怎麼處理方法 瀏覽:317
做生意都有哪些賺錢的方法 瀏覽:441
黃金三角手臂鍛煉方法 瀏覽:12
根號15在數軸上的表示方法圖片 瀏覽:913
語音提示器安裝方法 瀏覽:204
c32漏電保護空開連接方法 瀏覽:367
附件炎有哪些治療方法 瀏覽:335
36x198的簡便計算方法 瀏覽:258
高阻計使用方法 瀏覽:951
水質超標的解決方法 瀏覽:575
英語大師教學方法 瀏覽:155
男性眼袋怎麼消除簡單方法 瀏覽:907
鈦金條有幾種安裝方法好看 瀏覽:829
披薩餅的製作方法和視頻 瀏覽:387
青田玉鑒別方法 瀏覽:914