一、 什麼是多線程:
我們現在所使用操作系統都是多任務操作系統(早期使用的DOS操作系統為單任務操作系統),多任務操作指在同一時刻可以同時做多件事(可以同時執行多個程序)。
多進程:每個程序都是一個進程,在操作系統中可以同時執行多個程序,多進程的目的是為了有效的使用CPU資源,每開一個進程系統要為該進程分配相關的系統資源(內存資源)
多線程:線程是進程內部比進程更小的執行單元(執行流|程序片段),每個線程完成一個任務,每個進程內部包含了多個線程每個線程做自己的事情,在進程中的所有線程共享該進程的資源;
主線程:在進程中至少存在一個主線程,其他子線程都由主線程開啟,主線程不一定在其他線程結束後結束,有可能在其他線程結束前結束。Java中的主線程是main線程,是Java的main函數;
二、 Java中實現多線程的方式:
繼承Thread類來實現多線程:
當我們自定義的類繼承Thread類後,該類就為一個線程類,該類為一個獨立的執行單元,線程代碼必須編寫在run()方法中,run方法是由Thread類定義,我們自己寫的線程類必須重寫run方法。
run方法中定義的代碼為線程代碼,但run方法不能直接調用,如果直接調用並沒有開啟新的線程而是將run方法交給調用的線程執行
要開啟新的線程需要調用Thread類的start()方法,該方法自動開啟一個新的線程並自動執行run方法中的內容
java多線程的啟動順序不一定是線程執行的順序,各個線程之間是搶佔CPU資源執行的,所有有可能出現與啟動順序不一致的情況。
CPU的調用策略:
如何使用CPU資源是由操作系統來決定的,但操作系統只能決定CPU的使用策略不能控制實際獲得CPU執行權的程序。
線程執行有兩種方式:
1.搶占式:
目前PC機中使用最多的一種方式,線程搶佔CPU的執行權,當一個線程搶到CPU的資源後並不是一直執行到此線程執行結束,而是執行一個時間片後讓出CPU資源,此時同其他線程再次搶佔CPU資源獲得執行權。
2.輪循式;
每個線程執行固定的時間片後讓出CPU資源,以此循環執行每個線程執行相同的時間片後讓出CPU資源交給下一個線程執行。
希望對您有所幫助!~
2. java哪個框架的多線程源碼值得學習
最值得學的當屬Spring框架了。不過學之前還是先熟悉它裡面的各種概念好一些。 如果想零碎點學的話,Apache網站上的一些java工具,比如ant之類的,可以在了解其作用的情況下看源碼分析功能的實現。
3. 求JAVA多線程編程代碼
測試過了,沒問題。基本思路,實例化一個橋類,誰得到橋的可用標志誰過橋。
我第一個看到這個100分的,說實話,知道你是個學生要代碼而已,線程類好久沒練手了,練習一下而已,否則真不會給你寫代碼。因為我讀書的時候也發過類似的求助,知道什麼感受。不懂的時候真的沒辦法,所以告訴你思路。
package cn.thread;
public class Through_out_bridge {
public static void main(String[] args) {
Bridge b = Bridge.getInstance();//實例化橋
//實例化左端9個人,此時所有人都不能過橋,橋的可以狀態標志為不可以用
for (int i = 1; i <= 9; i++) {
Thread t = new Thread(new Person(false, i, b));
t.start();
}
//實例化右端12個人,此時所有人都不能過橋,橋的可以狀態標志為不可以用
for( int i=1 ;i<=12;i++)
{
Thread t = new Thread(new Person(true,i,b));
t.start();
}
//橋的可用狀態給左端第10個人,可以自定義給誰
b.state = true;
Thread t = new Thread(new Person(false, 10, b));
}
}
class Person implements Runnable {
public Bridge bridge;//橋
private String hand;//在橋哪一端
int No;//序號
public Person(boolean side, int i, Bridge bridge) {
this.No = i;
this.bridge = bridge;
if(bridge.state)
{
System.out.println(i+"已經過橋。");
}
if (side) {
this.hand = new String("右");
} else {
this.hand = new String("左");
}
}
//過橋方法
public synchronized void through() throws InterruptedException {
if (bridge.state) {
System.out.println(hand+"邊第"+No + "在過橋");
bridge.open( No);
} else {
bridge.lock(No);
}
}
public void run() {
try {
Thread.sleep(1000);
// System.out.println(No+hand+" 邊已經過橋!");
through();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Bridge {
//可用狀態判斷true:可用
public boolean state = false;
//自行實例化
public static Bridge getInstance() {
return new Bridge();
}
public synchronized void open(int i) throws InterruptedException {
if (state) {
Thread.sleep(1000);
this.state=true;
notify();
}
}
public synchronized void lock(int i) throws InterruptedException {
if (!state) {
this.state=false;
System.out.println(i + " 在等待.");
wait();
}
}
}
4. Java 程序中的多線程源代碼
你的問題倒讓人看不懂。。。首先這里是 C#/.net板塊,居然問了個java的問題。。。其次,內容看不懂?什麼內容看不懂?加代碼又是什麼?java程序中的多線程原碼是指什麼原碼。。。
5. 如何用Java編寫多線程
在java中要想實現多線程,有兩種手段,一種是繼續Thread類,另外一種是實現Runable介面。
對於直接繼承Thread的類來說,代碼大致框架是:
?
123456789101112 class 類名 extends Thread{ 方法1; 方法2; … public void run(){ // other code… } 屬性1; 屬性2; … }
先看一個簡單的例子:
?
/** * @author Rollen-Holt 繼承Thread類,直接調用run方法 * */class hello extends Thread { public hello() { } public hello(String name) { this.name = name; } public void run() { for (int i = 0; i < 5; i++) { System.out.println(name + "運行 " + i); } } public static void main(String[] args) { hello h1=new hello("A"); hello h2=new hello("B"); h1.run(); h2.run(); } private String name; }
【運行結果】:
A運行 0
A運行 1
A運行 2
A運行 3
A運行 4
B運行 0
B運行 1
B運行 2
B運行 3
B運行 4
我們會發現這些都是順序執行的,說明我們的調用方法不對,應該調用的是start()方法。
當我們把上面的主函數修改為如下所示的時候:
?
123456 public static void main(String[] args) { hello h1=new hello("A"); hello h2=new hello("B"); h1.start(); h2.start(); }
然後運行程序,輸出的可能的結果如下:
A運行 0
B運行 0
B運行 1
B運行 2
B運行 3
B運行 4
A運行 1
A運行 2
A運行 3
A運行 4
因為需要用到CPU的資源,所以每次的運行結果基本是都不一樣的,呵呵。
注意:雖然我們在這里調用的是start()方法,但是實際上調用的還是run()方法的主體。
那麼:為什麼我們不能直接調用run()方法呢?
我的理解是:線程的運行需要本地操作系統的支持。
如果你查看start的源代碼的時候,會發現:
?
1234567891011121314151617 public synchronized void start() { /** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state "NEW". */ if (threadStatus != 0 || this != me) throw new IllegalThreadStateException(); group.add(this); start0(); if (stopBeforeStart) { stop0(throwableFromStop); } } private native void start0();
注意我用紅色加粗的那一條語句,說明此處調用的是start0()。並且這個這個方法用了native關鍵字,次關鍵字表示調用本地操作系統的函數。因為多線程的實現需要本地操作系統的支持。
但是start方法重復調用的話,會出現java.lang.IllegalThreadStateException異常。
通過實現Runnable介面:
大致框架是:
?
123456789101112 class 類名 implements Runnable{ 方法1; 方法2; … public void run(){ // other code… } 屬性1; 屬性2; … }
來先看一個小例子吧:
?
2930 /** * @author Rollen-Holt 實現Runnable介面 * */class hello implements Runnable { public hello() { } public hello(String name) { this.name = name; } public void run() { for (int i = 0; i < 5; i++) { System.out.println(name + "運行 " + i); } } public static void main(String[] args) { hello h1=new hello("線程A"); Thread demo= new Thread(h1); hello h2=new hello("線程B"); Thread demo1=new Thread(h2); demo.start(); demo1.start(); } private String name; }
【可能的運行結果】:
線程A運行 0
線程B運行 0
線程B運行 1
線程B運行 2
線程B運行 3
線程B運行 4
線程A運行 1
線程A運行 2
線程A運行 3
線程A運行 4
關於選擇繼承Thread還是實現Runnable介面?
其實Thread也是實現Runnable介面的:
?
12345678 class Thread implements Runnable { //… public void run() { if (target != null) { target.run(); } } }
其實Thread中的run方法調用的是Runnable介面的run方法。不知道大家發現沒有,Thread和Runnable都實現了run方法,這種操作模式其實就是代理模式。關於代理模式,我曾經寫過一個小例子呵呵,大家有興趣的話可以看一下:http://www.cnblogs.com/rollenholt/archive/2011/08/18/2144847.html
Thread和Runnable的區別:
如果一個類繼承Thread,則不適合資源共享。但是如果實現了Runable介面的話,則很容易的實現資源共享。
?
/** * @author Rollen-Holt 繼承Thread類,不能資源共享 * */class hello extends Thread { public void run() { for (int i = 0; i < 7; i++) { if (count > 0) { System.out.println("count= " + count--); } } } public static void main(String[] args) { hello h1 = new hello(); hello h2 = new hello(); hello h3 = new hello(); h1.start(); h2.start(); h3.start(); } private int count = 5; }
【運行結果】:
count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1
大家可以想像,如果這個是一個買票系統的話,如果count表示的是車票的數量的話,說明並沒有實現資源的共享。
我們換為Runnable介面:
?
12345678910111213141516171819 /** * @author Rollen-Holt 繼承Thread類,不能資源共享 * */class hello implements Runnable { public void run() { for (int i = 0; i < 7; i++) { if (count > 0) { System.out.println("count= " + count--); } } } public static void main(String[] args) { hello he=new hello(); new Thread(he).start(); } private int count = 5; }
【運行結果】:
count= 5
count= 4
count= 3
count= 2
count= 1
總結一下吧:
實現Runnable介面比繼承Thread類所具有的優勢:
1):適合多個相同的程序代碼的線程去處理同一個資源
2):可以避免java中的單繼承的限制
3):增加程序的健壯性,代碼可以被多個線程共享,代碼和數據獨立。
所以,本人建議大家勁量實現介面。
?
6. java多線程編譯,求代碼!
public class Main {
private static ArrayBlockingQueue<String> file_q = new ArrayBlockingQueue<String>(1000);
private static ArrayBlockingQueue<String> console_q = new ArrayBlockingQueue<String>(1000);
public static void main(String[] args) {
new Thread(new Thread_A()).start();
new Thread(new Thread_B()).start();
new Thread(new Thread_C()).start();
}
static class Thread_A implements Runnable {
public void run() {
BufferedReader thread_a = new BufferedReader(new InputStreamReader(System.in));
String inputString;
while (true) {
try {
inputString = thread_a.readLine();
char firstChar = inputString.charAt(0);
if (firstChar >= 'A' && firstChar <= 'Z') {
file_q.put(inputString);//大寫,放入寫文件隊列
} else {
console_q.put(inputString);//非大寫,放入寫控制台隊列
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 文件輸出線程
*/
static class Thread_B implements Runnable {
public void run() {
while (true) {
try {
String to_write_file_str = file_q.poll(300L, TimeUnit.MILLISECONDS);
if (null != to_write_file_str && to_write_file_str.trim().length() > 0) {
RandomAccessFile randomFile = new RandomAccessFile("E:/test.txt", "rw");
long fileLength = randomFile.length();
randomFile.seek(fileLength);
randomFile.writeBytes(String.format("%s\r\n", to_write_file_str));
randomFile.close();
System.out.println("Thread B writed!");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 控制台輸出線程
*/
static class Thread_C implements Runnable {
public void run() {
while (true) {
try {
String to_write_console_str = console_q.poll(300L, TimeUnit.MILLISECONDS);
if (null != to_write_console_str && to_write_console_str.trim().length() > 0)
System.out.printf("Thread C say: %s%n", to_write_console_str);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
7. java多線程編程代碼如下,輸出結果如下:
首先,你同步的是具體的某個Test實例, 對於那個實例來說,實際上只有一個線程訪問了那個代碼塊,但是sum和other卻是多個線程同時去進行訪問,實際上這是不安全的,如果你想實現每次都輸出10000的效果,那麼正確的應該是在Test.class上加鎖,而不是獲取Test實例的鎖,修改後的代碼如下:
publicclassTestextendsThread{
publicstaticintsum=10000;
publicstaticintother=0;
publicvoidgetMoney(){
synchronized(Test.class){
System.out.println(Thread.currentThread().getName()+"開始執行");
sum=sum-100;
System.out.println("sum-100");
other=other+100;
System.out.println("other+100");
System.out.println(sum+other);
System.out.println(Thread.currentThread().getName()+"執行完成");
}
}
publicvoidrun(){
getMoney();
}
publicstaticvoidmain(String[]agrs){
Threadt[]=newThread[10];
for(inti=0;i<=9;i++){
t[i]=newTest();
t[i].start();
}
}
}
// 上面代碼能得到你的結果
8. 簡單Java多線程代碼求解
因為你new了兩次
試著在Task類內創建一個對象 然後鎖住這個對象
9. 求一個JAVA多線程例子,最好有代碼,謝謝啦!
package a.b.test;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Calculate1000 implements Callable<Integer>{
public Calculate1000(){}
public Calculate1000(int a, int b){
this.a = a;
this.b = b;
}
int a;
int b;
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//同步
Calculate1000 ca1 = new Calculate1000();
Date ds1 = new Date();
int result = 0;
for(int i = 1 ; i <= 1000 ; i++){
result = ca1.add(i, result);
}
System.out.println(result);
System.out.println("同步用時" + (new Date().getTime() - ds1.getTime()) + "MS");
//非同步
Date ds2 = new Date();
result = 0;
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Integer> future1 = es.submit(new Calculate1000(1,500));
Future<Integer> future2 = es.submit(new Calculate1000(501,1000));
result = future1.get() + future2.get();
System.out.println(result);
System.out.println("非同步用時" + (new Date().getTime() - ds2.getTime()) + "MS");
es.shutdown();
}
private int add(int a, int b) throws Exception{
Thread.sleep(10);
return a + b;
}
@Override
public Integer call() throws Exception {
int res = 0;
for(int i = a ; i <= b ; i++){
res = this.add(res, i);
}
return res;
}
}
樓主你試一下這段代碼行不行,行的話請採納!
10. 求java多線程遍歷目錄的完整代碼,能運行的那種
目錄結構為樹型結構,用多線程不大好做,線程最多在前幾層進行分割,比如每個目錄下有兩個目錄,共5層,那麼root目錄下就能啟用2個線程分別進行遍歷,所以第二層就啟動了2個線程進行遍歷,加上主線程共三個線程,雖然這樣做是可以做,但是要更具實際情況進行線程的規劃,否則容易線程過多導致cpu超負荷,或者假死,再提一點,遍歷目錄不建議用遞歸來寫,因為目錄較多容易棧溢出。
隨手寫了個,會有點bug就是關閉線程池的時候,還有就是有可能目錄太多進入拒絕策略,這個東西 可以考慮使用令牌桶演算法,或者計數器演算法來做。這里提供個簡單的例子。
public class TraverseUtil {
public static BlockingQueue blockingQueue = new LinkedBlockingQueue(100);
public static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(100,100,10, TimeUnit.SECONDS,blockingQueue);
public static void traverseFolder2(String path) {
File file = new File(path);
if (file.exists()) {
File[] files = file.listFiles();
if (null == files || files.length == 0) {
System.out.println("文件夾是空的!");
return;
} else {
for (File file2 : files) {
if (file2.isDirectory()) {
System.out.println("文件夾:" + file2.getAbsolutePath());
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
traverseFolder2(file2.getAbsolutePath());
}
});
} else {
System.out.println("文件:" + file2.getAbsolutePath());
}
}
}
} else {
System.out.println("文件不存在!");
}
}
public static void main(String[] args) throws InterruptedException {
traverseFolder2("C:\\Users\\a8932\\Desktop\\md");
}
}