線程的概念:
在一個程式中同時獨立運作的多個獨立流程,每一個獨立流程就是一個線程
線程的三要素:
CPU,Code,Data
程序:完成一個任務的過程
一個程序包括多個線程
線程是計算機執行的最小程式單元
線程并發
線程的開發:繼承Thread類與實作Runnable接口2種方式
1.繼承Thread類:
<b>public</b> <b>class</b> MyThread1 <b>extends</b> Thread {
<b>public</b> <b>void</b> run(){
<b>for</b>(<b>int</b> i=0;i<60;i++){
System. out.println("####" +i);
}
}
}
<b>public</b> <b>class</b> MyThread2 <b>extends</b> Thread{
System. out.println("$$$$" +i);
<b>public</b> <b>class</b> TestThread01 {
<b>public</b> <b>static</b> <b>void</b> main(String[] args) {
Thread t1= <b>new</b> MyThread1();
Thread t2= <b>new</b> MyThread2();
t1.start();
t2.start();
2.實作Runnable接口:
使用者開發一個類實作Ruannable接口
實作run()方法
運作線程
Ruannable target=new MyRunnable2();
Thread t3=new Thread(target);
<b>public</b> <b>class</b> MyThread03 <b>implements</b> Runnable{
<b>public</b> <b>void</b> run() {
<b>for</b>(<b>int</b> i=0;i<400;i++){
System. out.println("****" +i);
<b>public</b> <b>class</b> MyThread04 <b>implements</b> Runnable{
System. out.println("&&&&" +i);
<b>public</b> <b>class</b> TestThread3 {
Runnable runn3=<b>new</b> MyThread03();
Runnable runn4= <b>new</b> MyThread04();
Thread t3= <b>new</b> Thread(runn3);
Thread t4= <b>new</b> Thread(runn4);
t3.start();
t4.start();
繼承Thread是面向對象的程式設計方式
實作Runnable接口解決了單一繼承限制
線程的狀态:
初始狀态
Thread a=new Thread();
可運作狀态
a.start(),但此時未獲得CPU或者可運作狀态CPU時間片到期
運作狀态
可運作狀态獲得CPU
終結狀态
run()方法退出
sleep()方法
public static void sleep(long millis) throws InterruptedException
<b>for</b>(<b>int</b> i=0;i<10;i++){
<b>try</b> {
Thread. sleep(200);
} <b>catch</b> (InterruptedException e) {
}
運作結果:
$$$$0
####0
####1
$$$$1
$$$$2
####2
$$$$3
####3
####4
$$$$4
$$$$5
####5
$$$$6
####6
####7
$$$$7
####8
$$$$8
$$$$9
####9
join()方法:
join()方法也會導緻線程的阻塞
特點:如果目前線程中調用了另外一個線程join方法,
join()方法的問題:
如果兩個線程彼此調用對方的join方法,會導緻程式無法運作
解決方法如下:
public final void join(long millis) throws InterruptedException
Thread t;
<b>for</b>(<b>int</b> i=0;i<100;i++){
t.join(200);
e.printStackTrace();
線程同步:
多個線程并發通路同一個對象,如果破壞了不可分割的操作,進而就會造成資料不一緻。
臨界資源:多個線程并發通路同一個對象
原子操作:不可分割的操作
被多線程并發通路時,如果一個對象有可能出現資料不一緻的問題,那麼這個對象就稱為線程不安全的對象
如何解決多線程并發通路的問題
synchronized(object){
或者寫成synchronized(this){}
synchronized修飾方法
public synchronized void push(){}
死鎖:
用于解決死鎖的方法:wait()與notify()方法(這兩種方法也可進行線程間的通信)
生産者與消費者問題:
同時兩個線程操作一個棧,一個線程負責往棧中添加元素,一個線程負責删除棧中元素。
5.生産者與消費者問題
1.建立臨界資源(Stack) push(),pop(),print()
2.給push()與pop()方法加上線程同步
3.定義一個線程類,實作往Stack對象中存放那個相應資料,線上程中初始化臨界資源(Stack)
4.定義一個線程類,實作從Stack中取出相應資料,線上程中初始化臨界資源(Stack)
5.寫一個測試類,啟動3,4中建立的線程
6.運作5中的測試類進行測試,發現出現異常,分析異常,解決異常
異常原因:存資料時,字元數組大小固定導緻異常
取資料時,字元數組下标越界導緻異常
7.解決異常:在一中建立的臨界資源(Stack)中的push()方法中加入判斷,如果目前下标值==數組長度,則不能繼續存入資料,此時,通過線程的wait()方法,通知消費者從臨界資源讀取資料;
在一中建立的臨界資源(Stack)中的pop()方法中加入判斷,如果目前下标值==0,則不能繼續取出資料,此時,通過線程的notify()方法,通知生産者向臨界資源中存入資料
當生産者往臨界資源中存入資料時,需要通知消費者從臨界資源中讀取資料;
當消費者從臨界資源中取出資料時,需要通知生産者向臨界資源中存入資料;
//臨界資源
public class ProducerStack {
private char[] data=new char[12];
private int index=0;
public synchronized void push(char ch){
while(data.length==index){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
data[index]=ch;
/* try {
Thread.sleep(100);
}*/
index++;
this.notify();
System.out.println(ch+" push Stack:");
public synchronized void pop(String s){
System.out.println(s);
while(index==0){
index--;
System.out.println(data[index]+" pop Stack");
data[index]=' ';
public void print(String s){
for(int i=0;i<data.length;i++){
System.out.print(data[i]);
System.out.println();
//消費者
public class Consumer extends Thread {
ProducerStack ps;
public Consumer(ProducerStack ps) {
this.ps=ps;
}
public void run() {
ps.pop("pop01-----");
ps.print("pop-------");
//生産者
public class Producer extends Thread {
public Producer(ProducerStack ps) {
for(int i=0;i<20;i++){
ps.push('s');
}
ps.print("push----");
//測試類
public class TestProducer {
public static void main(String[] args) {
ProducerStack ps=new ProducerStack();
Thread p=new Producer(ps);
Thread con=new Consumer(ps);
p.start();
con.start();