黑马程序员---java基础------------------多线程
線程:就是進程中的一個獨立的控制單元。線程在控制著進程的執行。
線程的創建
一:繼承Thread類。步驟:
1,定義類繼承Thread。
2,復寫Thread類中的run方法。????? 目的:將自定義代碼存儲在run方法。讓線程運行。
class Demo extends Thread
{
? public void run()
? {
?? for(int x=0; x<60; x++)
??? System.out.println("demo run----"+x);
? }
}
3,調用線程的start方法,?????????????? 該方法兩個作用:啟動線程,調用run方法。
class ThreadDemo { ?
public static void main(String[] args) ?{ ?
?//for(int x=0; x<4000; x++) ??
//System.out.println("Hello World!");
?? Demo d = new Demo();//創建好一個線程。 ??
//d.start();//開啟線程并執行該線程的run方法。 ?
?d.run();//僅僅是對象調用方法。而線程創建了,并沒有運行。
?? ?? for(int x=0; x<60; x++) ???
System.out.println("Hello World!--"+x);
?}
? }
線程的運行狀態:
二:創建線程的第二種方式:實現Runable接口
步驟:
1,定義類實現Runnable接口
2,覆蓋Runnable接口中的run方法。 ?將線程要運行的代碼存放在該run方法中。
3,通過Thread類建立線程對象。
4,將Runnable接口的子類對象作為實際參數傳遞給Thread類的構造函數。
5,調用Thread類的start方法開啟線程并調用Runnable接口子類的run方法。
class Ticket implements Runnable//extends Thread {
private? int tick = 100;
public void run() { ?
while(true) { ??
if(tick>0) ??
System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--); ?
}
}
}
class? TicketDemo {?
public static void main(String[] args)? {
? Ticket t = new Ticket();
? Thread t1 = new Thread(t);//創建了一個線程;??
? Thread t2 = new Thread(t);//創建了一個線程;??
? Thread t3 = new Thread(t);//創建了一個線程;??
? Thread t4 = new Thread(t);//創建了一個線程;??
t1.start();?
? t2.start();?
? t3.start();?
? t4.start();
}
}
為什么要將Runnable接口的子類對象傳遞給Thread的構造函數?
? 因為,自定義的run方法所屬的對象是Runnable接口的子類對象。所以要讓線程去指定指定對象的run方法。就必須明確該run方法所屬對象。
實現方式和繼承方式有什么區別呢?
實現方式好處:避免了單繼承的局限性。在定義線程時,建議使用實現方式。
繼承Thread:線程代碼存放Thread子類run方法中。
實現Runnable,線程代碼存在接口的子類的run方法。
獲取當前線程對象:static Thread currentThread();
獲取線程名稱:getName();
?
class Test extends Thread {??
Test(String name) ?{ ??//父類有這樣的構造方法
super(name); ?
} ?
public void run() ?{ ??
for(int x=0; x<60; x++) ??{ ???
System.out.println((Thread.currentThread()==this)+"..."+this.getName()+" run..."+x); ??
}
?}
}
class ThreadTest
{
? public static void main(String[] args)
? {
?? Test t1 = new Test("one---");
?? Test t2 = new Test("two+++");
?? t1.start();
?? t2.start();
}
}
多線程的安全問題:通過分析,發現,打印出0,-1,-2等錯票。問題的原因:當多條語句在操作同一個線程共享數據時,一個線程對多條語句只執行了一部分,還沒有執
行完,另一個線程參與進來執行。導致共享數據的錯誤。解決辦法:對多條操作共享數據的語句,只能讓一個線程都執行完。在執行過程中,其他線程不可以參與執行。這就出來了
同步代碼塊
synchronized(對象) { ?
需要被同步的代碼
}
對象如同鎖。持有鎖的線程可以在同步中執行。 沒有持有鎖的線程即使獲取cpu的執行權,也進不去,因為沒有獲取鎖。
同步的前提:1,必須要有兩個或者兩個以上的線程;2,必須是多個線程使用同一個鎖。
好處:解決了多線程的安全問題。
弊端:多個線程需要判斷鎖,較為消耗資源。
class Ticket implements Runnable {
?private? int tick = 1000; ?
Object obj = new Object(); ?
public void run() ?{ ??
while(true) ??{ ???
synchronized(obj) ???{ ????
if(tick>0) ????{ ?????
//try{Thread.sleep(10);}catch(Exception e){} ????
?System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--); ???
?} ???
} ??
} ?
}
}
?
class? TicketDemo2 { ?
public static void main(String[] args) ?{
? ?Ticket t = new Ticket();
?? Thread t1 = new Thread(t); ??
? Thread t2 = new Thread(t); ??
? Thread t3 = new Thread(t); ??
??Thread t4 = new Thread(t); ??
? t1.start(); ?
?t2.start(); ??
? t3.start(); ??
? t4.start();
}
?}
同步函數:同步代碼塊用來封裝代碼的,函數也是來封裝代碼的,我們試圖讓函數具備同步性,也可以達到相同的效果。
class Bank { ?
private int sum;??
public synchronized void add(int n) ?{ ?
?sum = sum + n; ??
?try{Thread.sleep(10);
}catch(Exception e){} ???
System.out.println("sum="+sum);???
??}
}
class Cus implements Runnable {
?private Bank b = new Bank(); ?
? public void run() ?{?? ??
for(int x=0; x<3; x++) ??{
???b.add(100); ??
}
?}
}
class? BankDemo { ?
public static void main(String[] args) ?{
?? Cus c = new Cus(); ??
Thread t1 = new Thread(c); ??
Thread t2 = new Thread(c); ?
? t1.start(); ??
t2.start(); ?
}
}
驗證同步函數的鎖對象是this:如果直接將synchronized關鍵字放到run()?函數上做成同步函數,發現效果不行?,應為只啟動了0號線程,分析后得知,是同步的代碼沒弄清楚,后來將同步代碼部分提取后,封裝成獨立的show()函數調用并同步synchronized,就可以了。這個時候問一個問題,它的鎖是什么呢?函數需要被對象調用,函數都有一個所屬對象的引用時this所以同步函數的鎖對象是this。為了驗證,使用兩個線程買票,一個線程在同步代碼快中,一個在同步函數中,都在執行買票動作,如果要是同步就不會出現錯誤的票。
class Ticket implements Runnable { ?
private? int tick = 100; ?
//Object obj = new Object(); ?
boolean flag = true; ?
public? void run() ?{ ??
if(flag) ??{ ???
while(true) ???{ ????
//synchronized(this) ????{ ?????
if(tick>0) ?????{ ?????
? try{Thread.sleep(10);}catch(Exception e){} ??????
System.out.println(Thread.currentThread().getName()+"....code : "+ tick--); ?????
} ????
} ??
? } ??
} ??
? else ???
while(true) ????
show(); ?
}
?public synchronized void show()//this ?
{ ??
if(tick>0) ??{ ??
?try{Thread.sleep(10);}catch(Exception e){} ???
System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--); ??
} ?
}
}
class? ThisLockDemo {
?public static void main(String[] args) ?{
?? Ticket t = new Ticket();
?? Thread t1 = new Thread(t); ??
? Thread t2 = new Thread(t); ??
? t1.start(); ??
? try{
Thread.sleep(10);
}catch(Exception e){} ?
? t.flag = false; ??
t2.start();
? }
}
函數被靜態修飾后,使用的鎖是:類名.class
?
class Ticket implements Runnable { ?
private static? int tick = 100; ?
//Object obj = new Object();
?boolean flag = true; ?
public? void run() ?{ ??
if(flag) ??{ ??
? while(true) ???{ ????
synchronized(Ticket.class) ????{ ????
? if(tick>0) ?????{ ??????
try{Thread.sleep(10);}catch(Exception e){} ??????
System.out.println(Thread.currentThread().getName()+"....code : "+ tick--); ????
? } ????
} ???
} ??
} ??
else ???
while(true) ????
show(); ?
} ?
public static synchronized void show() ?{ ??
if(tick>0) ??{ ???
try{Thread.sleep(10);}catch(Exception e){} ???
System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--); ??
}??
}
}
?
class? StaticMethodDemo {
?public static void main(String[] args) ?{
?? Ticket t = new Ticket();
?? Thread t1 = new Thread(t); ??
? Thread t2 = new Thread(t); ?
?t1.start(); ??
? try{Thread.sleep(10);}catch(Exception e){} ??
? t.flag = false; ?
?t2.start();
?}
}
單例設計模式
懶漢式:
class Single { ?
private static Single s = null; ?
private Single(){}
? public static? Single getInstance() ?{ ??
if(s==null) ??{ ???
synchronized(Single.class) ???{ ????
if(s==null) ?????
//--->A; ?????
s = new Single(); ???
} ??
} ??
return s; ?
}
}
class SingleDemo { ?
public static void main(String[] args) ?{ ??
System.out.println("Hello World!"); ?
}
}
死鎖:
class Test implements Runnable { ?
private boolean flag; ?
Test(boolean flag) ?{ ??
this.flag = flag; ?
}
? public void run() ?{ ??
if(flag) ??{ ???
while(true) ???{ ????
synchronized(MyLock.locka) ????{ ?????
System.out.println(Thread.currentThread().getName()+"...if locka "); ?????
synchronized(MyLock.lockb) ?????{ ??????
System.out.println(Thread.currentThread().getName()+"..if lockb");????? ?????
} ????
} ???
} ??
} ??
else ??{ ???
while(true) ???{ ????
synchronized(MyLock.lockb) ????{ ?????
System.out.println(Thread.currentThread().getName()+"..else lockb"); ?????
synchronized(MyLock.locka) ?????{ ??????
System.out.println(Thread.currentThread().getName()+".....else locka"); ?????
} ????
} ???
} ??
} ?
}
}
class MyLock { ?
static Object locka = new Object(); ?
static Object lockb = new Object();
}
class? DeadLockTest { ?
public static void main(String[] args) ?{ ??
Thread t1 = new Thread(new Test(true)); ??
Thread t2 = new Thread(new Test(false)); ??
t1.start(); ??
t2.start(); ?
}
}
?
轉載于:https://www.cnblogs.com/zhaolibin198627/archive/2013/05/24/3097980.html
總結
以上是生活随笔為你收集整理的黑马程序员---java基础------------------多线程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++_004异常处理
- 下一篇: 应用SELinux中的目标策略限制进程运