Java併發編程知識點(1)基本的併發語句

實現多線程的兩種方式--Runnable和Thread/線程池

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MyRunnable implements Runnable{

	protected int countDown=10;
	private static int taskCount=0;
	private final int id = taskCount++;
	
	public MyRunnable(){}
	public MyRunnable(int countDown){
		this.countDown=countDown;
	}
	public void run(){
		while(countDown-->0){
			System.out.println("#"+id+" ("+(countDown>0?countDown:"liftoff!")+")");
			//告訴其他線程,讓同級其他線程執行
			Thread.yield();
		}
	}
	
	public static void main(String[]args){
		
		
		ExecutorService exe = Executors.newCachedThreadPool();
		for(int i=0;i<5;i++){
			//註釋處也可以正常運行
//			Thread t = new Thread(new MyRunnable());
//			t.start();
			exe.execute(new MyRunnable());
		}
		//如果不結束,將會一直運行,雖然沒有線程了。
		exe.shutdown();
		
	}
}

實現多線程主要有兩種方式,一種是實現Runnable接口,一種是直接繼承Thread類,兩種方式大同小異。實現多線程也可以實現匿名類的方式來實現。上面的例子使用了Runnable接口來實現一個多線程的併發,啓動線程有兩種那個方式,一種是Tread.start(),一種是使用線程池類似,來調用執行。使用線程池可以更好的管理線程,常見的線程池類型有CacheThreadPool,FixThreadPool,和SingleThreadPool.下面我們來看看FixedThreadPool和SingleThreadPool的執行的例子,我們分別寫一個main函數,來執行上面的過程,如下所示:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FixedThreadPool {
	public static void main(String[] args){
		//FixedThreadPool,設置線程池容量爲5
		ExecutorService exe = Executors.newFixedThreadPool(5);
		for(int i=0;i<10;i++){
			exe.execute(new MyRunnable());
		}
	}

}

上述沒有使用exe.shutdown()方法,我們來看看結果,運行結果如下:


可以看到,每次同時運行的線程只有5個,一開始運行的線程只有0,1,2,3,4,,o退出之後,5開始運行,1退出之後,6開始運行,這就是FixedThreadPool。同時你應該注意到,程序沒有結束,但是也不再打印新的東西了。

下面我們來看看SingleThreadPool的用法

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SingleThreadPool {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ExecutorService exe = Executors.newSingleThreadExecutor();
		for(int i=0;i<5;i++){
			exe.execute(new MyRunnable());
		}
		exe.shutdown();
		
	}

}
運行結果如下


可以看到無路如何,這些線程都是並行運行的。

有的時候你需要從你的線程返回你需要的值,你如果用Thread來實現,那是比較困難的。但是你可以用下面這種辦法啊。

import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class TaskWithResult implements Callable<Integer>{
	int begin;
	int end;
	
	public TaskWithResult(){
		
	}
	
	public TaskWithResult(int begin,int end){
		this.begin=begin;
		this.end=end;
	}

	@Override
	public Integer call() throws Exception {
		int total=0;
		for(int i=begin;i<end;i++){
			total+=i;
		}
		return total;
	}
	

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ExecutorService exe = Executors.newCachedThreadPool();
		ArrayList<Future<Integer>> futureList = new ArrayList<Future<Integer>>();
		for(int i=0;i<100000;i+=10000){
			futureList.add(exe.submit(new TaskWithResult(i,i+10000)));
		}
		exe.shutdown();
		int total=0;
		for(Future f:futureList){
			try {
				Integer i = (Integer) f.get();
				total+=i;
			} catch (InterruptedException | ExecutionException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(total);
		int total2=0;
		for(int i=0;i<100000;i++){
			total2+=i;
		}
		System.out.println(total2);
	}
}
具體的不多說,主要的思路就是實現了從0加到十萬。第一種辦法是使用了多線程的做法,分了是個線程,第二種做法是採用了直接加的做法。當然,也不一定誰好誰壞,這個要看虛擬機的支持了。

休眠/讓步/優先級/後臺線程和ThreadFactory

--sleep,以及TimeUnit類,可以自己參考jdk文檔;TimeUnit.[interval].sleep([length】)

--new Thread().yield()方法;
--new Thread(new Runnable()).setPriority(int) 以及new Thread(new Runnable).getPriority();Java一般有10級,分別從1-10;
--重點來說一下後臺線程,後臺線程也是有Thread的實例對象來調用的,只要你在使用start方法之前調用了setDaemon()方法,那麼你就能夠將線程變爲後臺線程。後臺線程有一個特性,那就是當前臺線程全部結束的時候,不管後臺線程有沒有結束,它都要全部結束,我們來看個後臺線程和ThradFactory結合的例子
import java.util.concurrent.*;

public class MyThreadFactory implements ThreadFactory{

	

	@Override
	public Thread newThread(Runnable r) {
		Thread t = new Thread(r);
		//將所有的線程都設置爲後臺線程
		t.setDaemon(true);
		return t;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		ExecutorService exe = Executors.newCachedThreadPool(new MyThreadFactory());
		for(int i=0;i<5;i++){
			exe.execute(new Mydaemon());
		}
		exe.shutdown();
		try {
			TimeUnit.SECONDS.sleep(10);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}
class Mydaemon implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<5;i++){
			try {
				TimeUnit.SECONDS.sleep(1);
				System.out.println(Thread.currentThread()+" "+this);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
}

加入一個線程,join的應用

一個線程可以在其他線程之上調用join()方法,其效果是等待一段時間直到第二個線程結束才繼續執行。如果某個線程在另一個線程t上調用t.join(),此線程將被掛起,直到目標線程結束才恢復。也可以加上一個超時參數,這樣如果目標線程在這段時間內到期時還沒有結束的話,join方法總是能反回,防止長時間等待。如下所示:


public class Sleeper extends Thread{
	
	public int duration;
	public Sleeper(String name, int sleepTime){
		super(name);
		this.duration = sleepTime;
		start();
	}
	
	public void run(){
		try{
			sleep(duration);
		}catch(InterruptedException e){
//			e.printStackTrace();
			System.out.println(getName()+" is interrupt");
			return;
		}
		System.out.println(getName()+" has awakened");
	}
	
	public static void main(String[] args){
		Sleeper
			sleeper1 = new Sleeper("sleeper1", 1500),
			sleeper2 = new Sleeper("sleeper2", 1500);
		Joiner
			Joiner1 = new Joiner("Joiner1", sleeper1),
			Joiner2 = new Joiner("joiner2", sleeper2);
		sleeper2.interrupt();
	}
}

class Joiner extends Thread{
	private Sleeper sleeper;
	public Joiner(String name,Sleeper sleeper){
		super(name);
		this.sleeper=sleeper;
		start();
	}
	
	public void run(){
		try{
			sleeper.join();
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		System.out.println(getName()+" join completed");
	}
	
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章