多線程基本知識

1、建立線程的三種方式

        其實建立線程遠遠不止有3種方式,但這裏只記錄三種。html

一、經過繼承Thread類來建立一個線程: 
步驟1:定義一個繼承Thread類的子類: 
步驟2:構造子類的一個對象: Thread t1 = new Thread(); 
步驟3:啓動線程: t1.start(); 
至此,一個線程就建立完成了。 java

二、經過實現Runnable接口來建立Thread線程: 
步驟1:建立實現Runnable接口的類: 
步驟2:建立一個類對象: Runnable runnable = new SomeRunnable(); 
步驟3:由Runnable建立一個Thread對象: Thread t2 = new Thread(runnable); 
步驟4:啓動線程: t2.start(); 
至此,一個線程就建立完成了。 
 
三、與方法2相似,經過實現Callable接口來建立Thread線程。
步驟1:建立實現Callable接口的類; 
步驟2:建立一個類對象: Callable callable = new SomeCallable(); 
步驟3:由Callable建立一個FutureTask對象: FutureTask ft= new FutureTask(callable); 
步驟4:由FutureTask建立一個Thread對象: Thread oneThread = new Thread(ft); 
步驟5:啓動線程: oneThread.start(); 
至此,一個線程就建立完成了。 dom

可參考:推薦:http://www.importnew.com/25286.htmlide

2、建立線程三種方式的demo

package resource.java.ordinary.mul.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 線程Demo
 * 
 * @author xiao
 */
public class TranditionThread {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		/*
		 * 建立線程的方法一:
		 */
		Thread thread = new Thread() {
			@Override
			public void run() {
				// excuMethod(1);
			}
		};
		thread.start();

		/*
		 * 建立線程方法二:
		 */
		Thread thread2 = new Thread(new Runnable() {
			@Override
			public void run() {
				// excuMethod(2);
			}
		});
		thread2.start();

		/*
		 * 建立線程方法三:
		 */
		// FutureTask是一個包裝器,它經過接受Callable來建立,它同時實現了 Future和Runnable接口。
		FutureTask<String> ft = new FutureTask<String>(new Callable<String>() {

			@Override
			public String call() throws Exception {
//				excuMethod(3);
				System.out.println("hi~~ 此處有個新線程");
				return "FutureTask 返回something";
			}
		});
		Thread t3 = new Thread(ft);
		t3.start();
		String result = ft.get();
		System.out.println(result);// 輸出: FutureTask 返回something

		/*
		 * 問題:此方法運行的是excuMethod(4)方法仍是excuMethod(5)方法??
		 */
		new Thread(new Runnable() {

			@Override
			public void run() {
//				excuMethod(4);
			}
		}) {
			@Override
			public void run() {
				// excuMethod(5);
			}
		}.start();
	}

	private static void excuMethod(int flag) {
		while (true) {
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(flag + "  " + Thread.currentThread().getName());
		}
	}

}

        對於上面問題的一個解答:this

        答案:運行標識爲5的線程。spa

        思路:這個方法的結構是這樣的:線程

new Thread( Runnable.run(){ 
		// 標識爲4的線程 
	}){ run(){ 
		// 標識爲5的線程 
    }}.start();

        緣由:在Thread.class中,Thread是實現了Runnable接口的。在運行了Thread.start()方法後,先在子類中找run()方法,找到則用子類的方法,找不到在用父類的方法。在這題中,標識爲5的線程所在的run()方法已經重寫了父類的方法,因此最終運行的是excuMethod(5)方法。code

附:Callable與Future的使用實例htm

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * Callable與Future的使用實例
 * @author xiao
 *
 */
public class CallableAndFuture {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ExecutorService threadPool = Executors.newSingleThreadExecutor();
		/*
		 * 獲取某一線程的返回結果:
		 * Callbale要採用ExecutorService的submit方提交,返回的future對象能夠取消任務, 也能夠獲取線程的返回結果。
		 * Future取得的結果類型和Callable返回的結果類型必須一致,這是經過泛型來實現的。
		 */
		Future<String> future = threadPool.submit(new Callable<String>() {
			@Override
			public String call() throws Exception {
				Thread.sleep(2000);
				return "hello"; // 返回結果 
			}
		});
		System.out.println("等待出結果");
		System.out.println("拿到結果" + future.get());// 獲取結果
		
		/*
		 * 獲取一組線程的返回結果:
		 * CompletionService用於提交一組Callable任務,其take方法放回已經完成的一個Callable任務對應的Future對象。
		 */
		ExecutorService threadPool2 = Executors.newFixedThreadPool(10);
		CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(threadPool2);
		for (int i = 1; i <= 10; i++) {
			final int seq = i;
			// 運行每一個線程的任務
			completionService.submit(new Callable<Integer>() {
				@Override
				public Integer call() throws Exception {
					Thread.sleep(new Random().nextInt(5000));
					return seq;
				}
			});
		}
		// 獲得全部線程運行的結果
		for (int i = 0; i < 10; i++) {
			System.out.println(completionService.take().get());
		}
		
	}
}

3、關於synchronized關鍵字

一、synchronized的四種用法:對象

(1)修飾方法

(2)修飾一個代碼塊

(3)修飾一個靜態方法

(4)修飾一個類

二、synchronized使用的demo

/**
 * 線程互斥:synchronized
 * @author xiao
 *
 */
public class TranditionThreadSynchronized {
	public static void main(String[] args) {
		new TranditionThreadSynchronized().init();
	}

	public void init() {
		final Output ootput = new Output();
		
		// 第一個線程
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					try {
						Thread.sleep(1000);
						ootput.output2("xiao");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}).start();

		// 第二個線程
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					try {
						Thread.sleep(1000);
						ootput.output2("hag");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
	}

	class Output {
		public void output(String name) {
			int len = name.length();
			// synchronized(XXX){}中,XXX表示的是要鎖住的對象
			// 此this指的是和output2中實現的效果同樣,鎖的是Output對象
			synchronized (this) {
				for (int i = 0; i < len; i++) {
					System.out.print(name.charAt(i));
				}
				System.out.println();
			}
		}

		public synchronized void output2(String name) {
			int len = name.length();
			for (int i = 0; i < len; i++) {
				System.out.print(name.charAt(i));
			}
			System.out.println();
		}
	}
}

        思考:若是須要在類Output中加入output3()方法(以下代碼塊所示),且output1()和output3()須要保持互斥,則須要作些什麼?         

public static synchronized void output3(String name) {
                int len = name.length();
                for (int i = 0; i < len; i++) {
                    System.out.print(name.charAt(i));
                }
                System.out.println();
            }

        答案:須要作的事情有:

    (1)內部類Output須要添加關鍵字static,以此變爲外部類。

    (2)將output1()中的synchronized (this)修改成synchronized (Output.class),使output1()方法中鎖定的是Output類。

s

相關文章
相關標籤/搜索