javase--6執行緒
執行緒
一、程序與執行緒的區別
執行緒是指程序內的一個執行單元,也是程序內的可排程實體.
與程序的區別:
(1)地址空間:程序內的一個執行單元;程序至少有一個執行緒;它們共享程序的地址空間;而程序有自己獨立的地址空間;
(2)資源擁有:程序是資源分配和擁有的單位,同一個程序內的執行緒共享程序的資源
(3)執行緒是處理器排程的基本單位,但程序不是.
4)二者均可併發執行.
程序和執行緒都是由作業系統所體會的程式執行的基本單元,系統利用該基本單元實現系統對應用的併發性。程序和執行緒的區別在於:
簡而言之,一個程式至少有一個程序,一個程序至少有一個執行緒.
執行緒的劃分尺度小於程序,使得多執行緒程式的併發性高。
另外,程序在執行過程中擁有獨立的記憶體單元,而多個執行緒共享記憶體,從而極大地提高了程式的執行效率。
執行緒在執行過程中與程序還是有區別的。每個獨立的執行緒有一個程式執行的入口、順序執行序列和程式的出口。但是執行緒不能夠獨立執行,必須依存在應用程式中,由應用程式提供多個執行緒執行控制。
從邏輯角度來看,多執行緒的意義在於一個應用程式中,有多個執行部分可以同時執行。但作業系統並沒有將多個執行緒看做多個獨立的應用,來實現程序的排程和管理以及資源分配。這就是程序和執行緒的重要區別。
程序是具有一定獨立功能的程式關於某個資料集合上的一次執行活動,程序是系統進行資源分配和排程的一個獨立單位.
執行緒是程序的一個實體,是CPU排程和分派的基本單位,它是比程序更小的能獨立執行的基本單位.執行緒自己基本上不擁有系統資源,只擁有一點在執行中必不可少的資源(如程式計數器,一組暫存器和棧),但是它可與同屬一個程序的其他的執行緒共享程序所擁有的全部資源.
一個執行緒可以建立和撤銷另一個執行緒;同一個程序中的多個執行緒之間可以併發執行.
二、執行緒的建立與執行
執行緒是通過建立java.lang.Thread類的例項來建立的,每個執行緒有執行緒體run( )完成操作,通過呼叫start( )來啟動執行緒
第一種方式:使用Runnable介面建立執行緒
1.可以將CPU,程式碼和資料分開,形成清晰的模型
2.執行緒體run()方法所在的類可以從其它類中繼承一些有用的屬性和方法
3.有利於保持程式的設計風格一致
第二種方式:直接繼承Thread類建立物件
public class TestThread1 {
public static void main(String args[]) {
//Thread t = new Thread(r);
//t.start();
r.start();
for(int i=0; i<100; i++) {
System.out.println("main:" + i);
}
}
}
//class Runner1 implements Runnable {
class Runner1 extends Thread {
public void run() {
for(int i=0; i<100; i++) {
System.out.println("Thread 1:" + i);
}
}
}
顯示:兩個輸出相互交替著輸出
三、執行緒的執行
執行緒的執行:建立-->就緒狀態--排程-->執行狀態--->終止 ;如果有導致阻塞的事件,進入阻塞狀態,阻塞解除,進入就緒狀態。
1.sleep( ) throws InterruptedException
呼叫interrupt( )可丟擲該異常
import java.util.Date;
public class TestInterrupt {
public static void main(String args[]) {
Runner2 r = new Runner2();
r.start();
try {
Thread.sleep(10000);//主執行緒睡眠
} catch(InterruptedException ex) {}
r.interrupt();//執行緒丟擲InterruptedException
}
}
class Runner2 extends Thread{
public void run() {
while(true) {
System.out.println("===="+new Date()+"====");
try {
sleep(1000); //睡眠1s
} catch(InterruptedException ex) {
return;
}
}
}
}
2.join( ) throws InterruptedException
將兩個執行緒合併,一個執行緒完成後進入第二個執行緒,相當於方法呼叫。
public class TestJoin {
public static void main(String args[]) {
Runner3 r = new Runner3("abc");
r.start();
try {
r.join();
} catch(InterruptedException ex) {}
for(int i=0; i<10; i++) {
System.out.println("I am main thread");
}
}
}
class Runner3 extends Thread {
Runner3(String s) {
super(s); //Thread(String s)為執行緒命名
}
public void run() {
for(int i=0; i<10; i++) {
System.out.println("I am" +getName());
try {
sleep(1000);
} catch(InterruptedException ex) {
return;
}
}
}
}
3.yield( )讓出CPU給另一個執行緒使用,即這個方法後,一定是另一個執行緒執行
public class TestYield {
public static void main(String args[]) {
Runner4 r1 = new Runner4("r1");
Runner4 r2 = new Runner4("r2");
r1.start();
r2.start();
}
}
class Runner4 extends Thread {
Runner4(String s) {
super(s);
}
public void run() {
for(int i=1; i<=100; i++) {
System.out.println(getName() +":"+i);
if(i % 10 == 0) {
yield();
}
}
}
}
4.setPriority( )與getPriority( )
優先順序1-10,Thread.MIN_PRIORITY=1;Thread.MAX_PRIORITY=10;Thread.NORM_PRIORITY=5; 預設為5
public class TestPriority {
public static void main(String args[]) {
Thread r1 = new Thread(new Runner5());
Thread r2 = new Thread(new Runner6());
r1.setPriority(Thread.MAX_PRIORITY);
r2.setPriority(Thread.MIN_PRIORITY);
r1.start();
r2.start();
}
}
class Runner5 implements Runnable {
public void run() {
for(int i=0; i<100; i++) {
System.out.println("r1:"+i);
}
}
}
class Runner6 implements Runnable {
public void run() {
for(int i=0; i<100; i++) {
System.out.println("r2:"+i);
}
}
}
四、同步
1.synchronized
程式在執行的時候,鎖定當前物件,有兩種方法
public class TestSync implements Runnable{
Timer timer = new Timer();
public static void main(String args[]) {
TestSync test = new TestSync();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
public void run() {
timer.add(Thread.currentThread().getName());
}
}
class Timer {
private static int num = 0;
public synchronized void add(String name) {
//synchronized(this) {
num ++;
try {
Thread.sleep(1);
} catch(InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(name+",你是第"+num+"個使用Timer的執行緒");
//}
}
}
五、wait( )
只要當類存在同步方法時可以在內部使用wait( ),代表使用該物件的執行緒被阻隔,而不是物件被阻隔。當執行緒wait時,所控制的鎖不歸該執行緒所有,必須要等到被叫醒後,在等到得到鎖之後才能進行後續操作。
對應的叫醒方法為notify( ),意思是叫醒wake在當前物件的一個執行緒。notifyall( )是叫醒wake在當前物件上的所有執行緒。
六、生產者和消費者實踐
package com.uestc;
public class ProducerConsumer {
public static void main(String args[]) {
SnyStack ss = new SnyStack();
Producer p = new Producer(ss);
Consumer c = new Consumer(ss);
new Thread(p).start();
new Thread(c).start();
}
}
class WoTou {
int id;
public WoTou(int id) {
this.id = id;
}
public String toString() {
return "WoTou-"+id;
}
}
class SnyStack {
int index = 0;
WoTou[] wt = new WoTou[6];
public synchronized void push(WoTou w) {
while(index == wt.length) {//注意,此次,防止因處理InterruptedException繼續執行下列程式碼,使用while,而不是if
try {
this.wait();
} catch(InterruptedException ex) {
ex.printStackTrace();
}
}
this.notify();//叫醒pop
wt[index] = w;
index ++;
}
public synchronized WoTou pop() {
while(index == 0) {
try {
this.wait();
} catch(InterruptedException ex) {
ex.printStackTrace();
}
}
this.notify();
index --;
return wt[index];
}
}
class Producer implements Runnable {
SnyStack ss = null;
public Producer(SnyStack ss) {
this.ss = ss;
}
public void run() {
for(int i=0; i<20; i++) {
WoTou w = new WoTou(i);
ss.push(w);
System.out.println("push: "+w.toString());
try {
Thread.sleep((int)Math.random() * 1000);
} catch(InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
SnyStack ss = null;
public Consumer(SnyStack ss) {
this.ss = ss;
}
public void run() {
for(int i=0; i<20; i++) {
WoTou w = ss.pop();
System.out.println("pop: "+w.toString());
try {
Thread.sleep((int)Math.random() * 5000);
} catch(InterruptedException ex) {
ex.printStackTrace();
}
}
}
}