Java安全執行緒的計數器__Java

來源:互聯網
上載者:User
   一、多線程以及安全執行緒           java安全執行緒就是指控制多個線程對某個資源的有序訪問或修改。這涉及兩個很重要的概念:java的記憶體模型和java的線程同步機制。       1.java的記憶體模型 要解決兩個主要的問題:可見度和有序性 可見度: 多個線程之間是不能互相傳遞資料通訊的,它們之間的溝通只能通過共用變數來進行       2.線程同步        由於同一進程內的多個線程共用記憶體空間,在Java中,就是共用執行個體,當多個線程試圖同時修改某個執行個體的內容時,就會造成衝突,因此,線程必須實現共用互斥,使多線程同步。        最簡單的同步是將一個方法標記為synchronized,對同一個執行個體來說,任一時刻只能有一個synchronized方法在執行。當一個方法正在執行某個synchronized方法時,其他線程如果想要執行這個執行個體的任意一個synchronized方法,都必須等待當前執行synchronized方法的線程退出此方法後,才能依次執行。        但是,非synchronized方法不受影響,不管當前有沒有執行synchronized方法,非synchronized方法都可以被多個線程同時執行。        synchronized和volatile關鍵字的區別:        (1)synchronized關鍵字保證了多個線程對於同步塊是互斥的,synchronized作為一種同步手段,解決java多線程的執行有序性和記憶體可見度,而volatile關鍵字只解決多線程的記憶體可見度問題;        (2)volatile關鍵字是java提供的一種同步手段,只不過它是輕量級。volatile只能保證多線程的記憶體可見度,不能保證多線程的執行有序性。而最徹底的同步要保證有序性和可見度,例如synchronized。        任何被volatile修飾的變數,都不拷貝副本到工作記憶體,任何修改都及時寫在主存。因此對於Valatile修飾的變數的修改,所有線程馬上就能看到,但是volatile不能保證對變數的修改是有序的。       3.基本知識 JAVA多線程實現方式:繼承Thread類、實現Runnable介面 使用哪一種:http://www.cnblogs.com/rollenholt/archive/2011/08/28/2156357.html 最好是後一種 二、執行個體代碼 功能:編寫一個安全執行緒的計數器,5個線程同時跑,計數到1000,輸出線程名和計數直到1000 代碼:
import java.util.concurrent.CountDownLatch;import java.util.concurrent.atomic.AtomicInteger;/*** 功能:安全執行緒的計數器,5個線程同時跑,計數到1000,輸出線程名和計數* @author Yolanda**/public class MySafeThread implements Runnable{     private static AtomicInteger count = new AtomicInteger(0);//安全執行緒的計數變數     private int threadCount = 0;//線程編號     private static int num = 1;     /**     * 功能:計數     */     public static void calc(){          while((count.get())<1000)          {               count.incrementAndGet();//自增1,返回更新值              System.out.println("正在運行是線程" + Thread.currentThread().getName() + ":" + count);                   }     }          /**     * 功能:線程運行方法,每次只能一個線程訪問     */     public synchronized void run() {          while(true)          {               try {                    Thread.sleep(1);               } catch (InterruptedException e) {                    e.printStackTrace();               }                    MySafeThread.calc();          }     }          public static void main(String[] args) {                    //建立五個線程執行個體並啟動          for (int i = 1; i < 6; i++) {                    Thread mySafeThread = new Thread(new MySafeThread());               mySafeThread.start();          }     }     }




結果:

 

正在運行是線程Thread-1:2

正在運行是線程Thread-4:4

正在運行是線程Thread-0:4

正在運行是線程Thread-3:2

正在運行是線程Thread-3:9

正在運行是線程Thread-3:10

正在運行是線程Thread-0:8

正在運行是線程Thread-4:7

正在運行是線程Thread-4:13

正在運行是線程Thread-4:14

正在運行是線程Thread-4:15

正在運行是線程Thread-4:16

正在運行是線程Thread-4:17

正在運行是線程Thread-4:18

正在運行是線程Thread-4:19

正在運行是線程Thread-4:20 ......

正在運行是線程Thread-4:988

正在運行是線程Thread-4:989

正在運行是線程Thread-4:990

正在運行是線程Thread-4:991

正在運行是線程Thread-4:992

正在運行是線程Thread-4:993

正在運行是線程Thread-4:994

正在運行是線程Thread-4:995

正在運行是線程Thread-4:996

正在運行是線程Thread-4:997

正在運行是線程Thread-4:998

正在運行是線程Thread-4:999

正在運行是線程Thread-4:1000

正在運行是線程Thread-2:399

正在運行是線程Thread-1:398

正在運行是線程Thread-0:700

正在運行是線程Thread-3:402

===========================我是更新線==============================

看上面的結果其實是有一點不對的,前面的幾個計數發生了重複,這是由於鎖的位置不正確導致的。所以對這個程式重寫了一下。

package com.yolanda.fun.thread;import java.util.concurrent.atomic.AtomicInteger;public class MySafeCalcThread1 implements Runnable {private static AtomicInteger count = new AtomicInteger(0);    public synchronized static void calc() {    if ((count.get()) < 1000) {    int c = count.incrementAndGet();// 自增1,返回更新值    System.out.println("正在運行是線程" + Thread.currentThread().getName() + ":" + c);    }}public void run() { while(true)         { MySafeCalcThread1.calc(); try { Thread.sleep(0); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }          }}public static void main(String[] args) {for (int i = 0; i < 6; i++) {MySafeCalcThread1 thread = new MySafeCalcThread1();Thread t = new Thread(thread);t.start();}}}

然後結果就對啦,就沒有重複計數的問題啦。


結果:

正在運行是線程Thread-0:1
正在運行是線程Thread-1:2
正在運行是線程Thread-0:4
正在運行是線程Thread-2:3
正在運行是線程Thread-2:7
正在運行是線程Thread-0:6
正在運行是線程Thread-0:9
正在運行是線程Thread-1:5
正在運行是線程Thread-0:12
正在運行是線程Thread-5:11
正在運行是線程Thread-3:10
正在運行是線程Thread-2:8

.......

正在運行是線程Thread-4:996
正在運行是線程Thread-4:997
正在運行是線程Thread-4:998
正在運行是線程Thread-4:999
正在運行是線程Thread-4:1000
正在運行是線程Thread-1:743
正在運行是線程Thread-3:742
正在運行是線程Thread-0:935
正在運行是線程Thread-5:884
正在運行是線程Thread-2:747


還有一種寫法是這樣子的~

package com.yolanda.fun.thread;import java.util.concurrent.atomic.AtomicInteger;public class MySafeCalcThread2 implements Runnable {private static AtomicInteger count = new AtomicInteger(0);public static void calc() {while ((count.get()) < 1000) {int c = 0;synchronized (count) {if ((count.get()) < 1000) {c = count.incrementAndGet();// 自增1,返回更新值}}System.out.println("正在運行是線程" + Thread.currentThread().getName() + ":" + c);}}public void run() { while(true)         { MySafeCalcThread2.calc(); try { Thread.sleep(0); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }          }}public static void main(String[] args) {for (int i = 0; i < 6; i++) {MySafeCalcThread2 thread = new MySafeCalcThread2();Thread t = new Thread(thread);t.start();}}}



結果:

正在運行是線程Thread-0:1
正在運行是線程Thread-3:2
正在運行是線程Thread-4:3
正在運行是線程Thread-5:4
正在運行是線程Thread-0:5
正在運行是線程Thread-0:6
正在運行是線程Thread-2:7
正在運行是線程Thread-2:8
正在運行是線程Thread-1:9
正在運行是線程Thread-2:10

........

正在運行是線程Thread-2:990
正在運行是線程Thread-2:991
正在運行是線程Thread-2:992
正在運行是線程Thread-1:993
正在運行是線程Thread-2:994
正在運行是線程Thread-0:995
正在運行是線程Thread-5:996
正在運行是線程Thread-5:997
正在運行是線程Thread-5:998
正在運行是線程Thread-5:999
正在運行是線程Thread-5:1000


============================我是更新線===============================

在此處補充一下JAVA多線程實現的兩種方式

第一種:繼承Thread類

package com.yolanda.fun.thread;public class MyThread extends Thread {public void run() {for (int i = 0; i < 10; i++) {System.out.println("線程" + Thread.currentThread().getName() + "在運行");}}public static void main(String[] args) {MyThread thread = new MyThread();thread.start();for (int i = 0; i < 10; i++) {System.out.println("線程" + Thread.currentThread().getName() + "在運行");// 線程main}}}



結果:

線程main在運行
線程Thread-0在運行
線程main在運行
線程main在運行
線程Thread-0在運行
線程Thread-0在運行
線程main在運行
線程Thread-0在運行
線程main在運行
線程Thread-0在運行
線程Thread-0在運行
線程Thread-0在運行
線程Thread-0在運行
線程Thread-0在運行
線程Thread-0在運行
線程main在運行
線程main在運行
線程main在運行
線程main在運行
線程main在運行


結果分析:這裡可以看到main線程和Thread-0線程交替運行。

所謂的多線程,指的是兩個線程的代碼可以同時運行,而不必一個線程需要等待另一個線程內的代碼執行完才可以運行。對於單核CPU來說,是無法做到真正的多線程的,每個時間點上,CPU都會執行特定的代碼,由於CPU執行代碼時間很快,所以兩個線程的代碼交替執行看起來像是同時執行的一樣。那具體執行某段代碼多少時間,就和分時機制系統有關了。分時系統把CPU時間劃分為多個時間片,作業系統以時間片為單位片為單位各個線程的代碼,越好的CPU分出的時間片越小。所以看不到明顯效果也很正常,一個線程列印5句話本來就很快,可能在分出的時間片內就執行完成了。所以,最簡單的解決辦法就是把for迴圈的值調大一點就可以了(也可以在for迴圈裡加Thread.sleep方法)。


第二種:實現Runnable介面。和繼承自Thread類差不多,不過實現Runnable後,還是要通過一個Thread來啟動


package com.yolanda.fun.thread;public class MyRunnable implements Runnable{public void run() {for (int i = 0; i < 10; i++) {System.out.println("線程" + Thread.currentThread().getName() + "在運行");}}public static void main(String[] args) {MyRunnable thread = new MyRunnable();Thread t = new Thread(thread);t.start();for (int i = 0; i < 10; i++) {System.out.println("線程" + Thread.currentThread().getName() + "在運行");}}}


結果:

線程main在運行
線程Thread-0在運行
線程main在運行
線程Thread-0在運行
線程main在運行
線程Thread-0在運行
線程main在運行
線程main在運行
線程main在運行
線程main在運行
線程main在運行
線程main在運行
線程main在運行
線程Thread-0在運行
線程Thread-0在運行
線程Thread-0在運行
線程Thread-0在運行
線程Thread-0在運行
線程Thread-0在運行
線程Thread-0在運行


兩個線程也是交替運行。


其實Thread類也是實現的Runnable介面。


兩種實現方式對比的關鍵就在於extends和implements的對比,當然是後者好。因為第一,繼承只能但繼承,實現可以多實現;第二,實現的方式對比繼承的方式,也有利於減小程式之間的耦合。

因此,多線程的實現幾乎都是使用的Runnable介面的方式。


線程狀態

虛擬機器中的線程狀態有六種,定義在Thread.State中:


1、建立狀態NEW
new了但是沒有啟動的線程的狀態。比如"Thread t = new Thread()",t就是一個處於NEW狀態的線程

2、可運行狀態RUNNABLE
new出來線程,調用start()方法即處於RUNNABLE狀態了。處於RUNNABLE狀態的線程可能正在Java虛擬機器中運行,也可能正在等待處理器的資源,因為一個線程必須獲得CPU的資源後,才可以運行其run()方法中的內容,否則排隊等待

3、阻塞BLOCKED
如果某一線程正在等待監視器鎖,以便進入一個同步的塊/方法,那麼這個線程的狀態就是阻塞BLOCKED

4、等待WAITING
某一線程因為調用不帶逾時的Object的wait()方法、不帶逾時的Thread的join()方法、LockSupport的park()方法,就會處於等待WAITING狀態

5、逾時等待TIMED_WAITING
某一線程因為調用帶有指定正等待時間的Object的wait()方法、Thread的join()方法、Thread的sleep()方法、LockSupport的parkNanos()方法、LockSupport的parkUntil()方法,就會處於逾時等待TIMED_WAITING狀態

6、終止狀態TERMINATED
線程調用終止或者run()方法執行結束後,線程即處於終止狀態。處於終止狀態的線程不具備繼續啟動並執行能力。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.