java基礎之線程

java基礎之線程

一.概述

    1.1  簡介

        線程是java的編程中的重中之重,弄清概念是一個程序員的基本功。下面介紹下線程相關的基本概念和實現。java

    1.2 進程

        計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位(指一個內存中運行的應用程序,每一個進程都有本身獨立的一塊內存空間,一個進程中能夠啓動多個線程)
程序員

    1.3 線程

        有時被稱爲輕量級進程(Lightweight Process,LWP),是程序執行流的最小單元(cpu運行)。一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程本身不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的所有資源。編程

        tips:這裏形容下,一個應用程序至關於一個倉庫,而一個線程至關於一個取貨單。有一個管理員(cpu),每一隻能取一個商品(計算結果)。管理員不會一次把一個單子的商品取完,而是隨機按着一個單子的順序取一個商品,而後隨機按另一個單子取貨。
安全

    1.4 .線程狀態 

        java中的實現:
ide

            a) 新生態:new Thread()對象,這個對象封裝了JVM啓動一個新線程的方式,當start()後將控制權交給程序計數器,生成新的線程。
this

            b) 就緒狀態「在程序計數器列表中、等待CPU的使用權<start(),notify(),nitify all(),I/O完成>spa

            d) 運行狀態:佔用cpu時間,進行邏輯運算。<run(),等待調度器調用>線程

            e) 阻塞狀態:處於不正常的運行和等待中。<jion(),wait(),sleep(),suspend(),I/O請求>指針

            f) 死亡狀態: 運行完成、強行中止。<stop()、destory()>code

    1.5 線程總結

        1. 只有run()狀態能夠直接獲取數據的使用權

        2. 線程的研究主要是在運行狀態和阻塞狀態。 

        3. 線程雖然有優先級,可是JVM並非100%安裝優先級來調用。隨機錯亂的調用方式

        4. 阻塞的方式:一種是sleep(),整個線程讓調度器中止調度。一種是線程在對象鎖的等待序列上。

        5. 抽象一個圖,便於記憶:線程會在紅色部分中止調度,只有在在可執行序列纔會被調度。

二.案例

    2.1 線程名

       每個線程都會有一個線程名。

          a)主線程名:程序的啓動線程接---線程名:main

          b)默認線程名: thread-N(N是數字)

          c)自定義線程名

/**
 * @see 線程名
 * 
 * @author ssHss
 *
 */
public class ThreadName implements Runnable {

	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getName());// main
		ThreadName tn = new ThreadName();
		Thread tr = new Thread(tn);//線程名:thread-0
		Thread tr2 = new Thread(tn, "tr2");//線程名:tr2
		tr.start();
		tr2.start();
	}

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName());
	}
}

    2.2 阻止當前線程:下面幾種都不會釋放對象鎖

        a)Thread.yield():讓步,建議具備相同優先級的其它線程能夠運行了

/**
 * @see yield:將當前線程從運行態放入到可運行態、將CPU交給線程優先級高的線程
 * @author ssHss
 *
 */
public class ThreadYield implements Runnable {

	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getName() + " start");
		ThreadYield ty = new ThreadYield();
		// 線程1
		Thread t1 = new Thread(ty, "t--1");
		t1.setPriority(8);// 默認的優先級爲5
		// 線程2
		Thread t2 = new Thread(ty, "t--2");
		// t1.setPriority(8);

		t1.start();
		t2.start();
		System.out.println(Thread.currentThread().getName() + " end");
	}

	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + " :獲取了 : " + i);
			if (i % 3 == 0) {
				Thread.yield();
			}
		}
	}

}

         b)Thread.sleep(x毫秒):讓當前線程阻塞x毫秒。

        c) join():一個線程在其餘線程上調用join()方法,其效果將其它線程排在本線程後面。

/**
 * @see t.JOIN:將當前線程加入到t線程的後面
 *
 */
public class ThreadJoin {
	public static void main(String[] args) throws InterruptedException {
		Sleeper sleepy = new Sleeper("Sleeper", 1500);
		Sleeper grumpy = new Sleeper("Grumpy", 1500);
		Joiner dopey = new Joiner("Dopey", sleepy);
		Joiner doc = new Joiner("Doc", grumpy);
		grumpy.interrupt();
	}

}

class Sleeper extends Thread {

	private int duration;

	public Sleeper(String name, int sleepTime) {
		super(name);
		duration = sleepTime;
		this.start();
	}

	public void run() {
		try {
			Thread.sleep(duration);
		} catch (Exception e) {
			System.out.println(this.getName() + " was interrupted " + this.isInterrupted());
		}
		System.out.println(this.getName() + " has awakened");
	}
}

class Joiner extends Thread {
	private Sleeper sleeper;

	public Joiner(String name, Sleeper sleeper) {
		super(name);
		this.sleeper = sleeper;
		this.start();
	}

	public void run() {
		try {
			sleeper.join();
		} catch (Exception e) {
			System.out.println("Ineterrupted");
		}
		System.out.println(this.getName() + " join completed");
	}
}

    3.3 Executors:執行器

public class Executor {

	/**
	 * @see Executor:線程池,管理線程的建立和銷燬
	 * @param args
	 */
	public static void main(String[] args) {
		//ExecutorService es = Executors.newCachedThreadPool();//建立與所需線程相同數量的線程,回收舊線程時中止新建線程
		//ExecutorService es = Executors.newFixedThreadPool(5);//建立固定數量的線程。
		ExecutorService es = Executors.newSingleThreadExecutor();//建立單個線程,而後排隊執行
		for (int i = 0; i < 5; i++) {
			es.execute(new TestClass());
		}
		es.shutdown();
	}
}

class TestClass implements Runnable {

	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + " i-->" + i);
		}
	}

}

     3.4 synchronized: 對象鎖

        a)每一個對象都有一個對象鎖,保證線程在操做數據時的,數據一致性。

        c)獲取了這個鎖,就獲取了這個的資源控制權。其它線程只有去對象的對象鎖列表(阻塞狀態),等待鎖釋放。在釋放鎖的時候,會把全部對象鎖列表中的線程都移動到可運行列表中。

        b)釋放鎖的方式:(理解記憶)

            1.自動釋放鎖(運行完):將對象鎖列表中的線程都移動到可運行狀態列表,包括本身,而後釋放鎖。全部線程都是可執行狀態,而後搶佔鎖的使用權。

            2.wait釋放鎖 :把本身加入到對象鎖列表,並釋放鎖。可是不清理對象鎖列表。

           Tips:1.當獲取對象鎖的時候(synchronzied),會同將鎖裏面調用的對象一塊兒鎖定(當前對象的嵌套、其它對象的調用)。

        c)因爲對象鎖synchronized使用:

            非靜態方法:synchronized(this) 鎖的是堆中的地址空間。

            靜態方法:synchronized(xxxx.class) 鎖的是class 文件存放在永久區的地址空間。通常靜態變量最好是放在靜態方法中執行,保證安全行。

/**
 * @see 生存者、消費者模式
 * @author ssHss
 *
 */
public class ThreadSynChron implements Runnable {

	Test tc = null;

	public static void main(String[] args) {
		System.out.println(Thread.currentThread().getName() + " START");
		Test test = new Test();
		ThreadSynChron tsc = new ThreadSynChron(test);
		Thread t1 = new Thread(tsc);
		Thread t2 = new Thread(tsc);
		t1.start();
		t2.start();
	}

	public ThreadSynChron(Test test) {
		this.tc = test;
	}

	public void A() {
		synchronized (this) {
			System.out.println(Thread.currentThread().getName() + "  A  ");
			this.B();
		}
	}

	public void B() {
		synchronized (this) {
			System.out.println(Thread.currentThread().getName() + "  B  ");
			tc.TestC();
		}
	}

	@Override
	public void run() {
		synchronized (this) {
			System.out.println(Thread.currentThread().getName() + "  run  ");
			this.A();
		}
	}
}

class Test {
	public void TestC() {
		synchronized (this) {
			System.out.println(Thread.currentThread().getName() + " TestC  ");
			this.TestD();
		}
	}

	public void TestD() {
		synchronized (this) {
			System.out.println(Thread.currentThread().getName() + " TestD  ");
		}
	}

	public void TestE() {
		synchronized (this) {
			System.out.println(Thread.currentThread().getName() + " TestE  ");
		}
	}

	public void TestF() {
		synchronized (this) {
			System.out.println(Thread.currentThread().getName() + " TestF  ");
		}
	}

	public void TestG() {
		synchronized (this) {
			System.out.println(Thread.currentThread().getName() + " TestG  ");
		}
	}
}

。

    3.5 線程交互:wait,notify,notify all (只能在對象鎖synchronized有用)

        理解記憶:

        a)wait:把本身加入到對象鎖列表

        b)nitify:先將對象鎖列表中的線程移動到可執行序列,告訴JVM調度器,本對象的使用權即將可用。請作好準備,請在對象鎖釋放後調用。

package thread;

/**
 * @see 消費這生產者
 * @author ssHss
 *
 */
public class CustomerProduce {
	public static void main(String[] args) {
		Store st = new Store();
		Customer2 ctom = new Customer2(st);
		Producer pdc = new Producer(st);
		Thread t1 = new Thread(ctom);
		Thread t2 = new Thread(pdc);
		t1.start();
		t2.start();
	}
}

// 消費者
class Customer2 implements Runnable {
	public Store store;
	public Customer2(Store store) {
		this.store = store;
	}
	@Override
	public void run() {
		synchronized (store) {
			System.out.println(Thread.currentThread().getName() + " 開始消費 ");
			try {
				this.store.customer();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "  消費結束 ");
		}
	}
}
// 生成者
class Producer implements Runnable {
	public Store store;
	public Producer(Store store) {
		this.store = store;
	}
	@Override
	public void run() {
		synchronized (store) {
			System.out.println(Thread.currentThread().getName() + " 開始生產 ");
			try {
				this.store.produce();
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "  生存結束 ");
		}
	}
}
// 倉庫
class Store {
	private int breadNumber; // 總共
	private int afterNumber; // 剩餘
	// 生成
	public void produce() throws InterruptedException {
		synchronized (this) {
			for (int i = 0; i < 20; i++) {
				// 若是還有剩餘大於0,則喚醒
				if (afterNumber > 0)
					this.notify();
				// 若是大於5,則等待
				if (afterNumber > 5)
					this.wait();
				breadNumber++;
				afterNumber++;
				System.out.println(Thread.currentThread().getName() + " 生產了麪包: " + breadNumber + " 剩餘 " + afterNumber);
			}
			this.notify();
		}
	}
	// 消費
	public void customer() throws InterruptedException {
		synchronized (this) {
			for (int i = 0; i < 15; i++) {
				if (afterNumber <= 2)
//					this.notify();
				// 若是還有剩餘==0,則等待
				if (afterNumber == 0)
					this.wait();
				afterNumber--;
				System.out.println(Thread.currentThread().getName() + " 消費了麪包: " + breadNumber + " 剩餘 " + afterNumber);
			}
			this.notify();
		}
	}
}


        最開始執行狀態:

        調用notify():

        調用:wait()

        執行結果:

相關文章
相關標籤/搜索