java多线程多态_Java学习之多线程
多線程:
(一)進程與線程
進程特點
并發(fā)與并行的區(qū)別:
多線程編程的好處:
(二)多線程的建立
1,通過繼承Thread類,代碼如下:
class MyThread extendsThread {private static int K = 10;//類共享變量
private int M=10;//成員共享變量
MyThread(){super();
}
@Overridepublic voidrun() {
System.out.println("in MyThread run");for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+ "K:" + K--);
System.out.println(Thread.currentThread().getName()+ "M:" + M--);
}
}
}public classThreadDemo1 {public static voidmain(String[] args) {//多線程Thead方式1
MyThread thread2 = newMyThread();new Thread(thread2,"t2").start();//此時成員變量被共享,靜態(tài)也被共享,k和M的結果為-9
new Thread(thread2,"t3").start();//多線程Thead方式1
MyThread thread3=new MyThread();//此時靜態(tài)類變量被共享,k為-9,M為0.
thread2.start();
thread3.start();
}
}
2,通過實現Runnable接口(推薦),代碼如下:
public classThreadDemo1 {public static voidmain(String[] args) {//RUNNABLE 方式2
MyRunnable myRunnable = newMyRunnable();new Thread(myRunnable,"t1").start();//此時成員變量被共享,靜態(tài)也被共享,K和M為-9//RUNNABLE 方式2
new Thread(myRunnable,"t3").start();
MyRunnable myRunnable1= new MyRunnable();//此時成員變量不被共享,靜態(tài)被共享,K為-9,M為0
new Thread(myRunnable,"t1").start();new Thread(myRunnable1,"t3").start();
}
}class MyRunnable implementsRunnable {private static int K = 10;private int M = 10;
@Overridepublic voidrun() {
System.out.println("in MyRunnable run");for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+ " K:" + (K--));
System.out.println(Thread.currentThread().getName()+ " M:" + (M--));
}
}
}
3,通過實現Callable接口和Future包裝來建立:
importjava.util.Random;importjava.util.concurrent.Callable;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.FutureTask;public classCallableThread {public static voidmain(String[] args) {
Callable callable = new Callable() {public Integer call() throwsException {return new Random().nextInt(100);
}
};
FutureTask future = new FutureTask(callable);newThread(future).start();try{
Thread.sleep(5000);//可能做一些事情
System.out.println(future.get());
}catch(InterruptedException e) {
e.printStackTrace();
}catch(ExecutionException e) {
e.printStackTrace();
}
}
}
View Code
三種建立多線程的優(yōu)劣比較有:
(三)線程的生命周期
Java線程具有五中基本狀態(tài)
新建狀態(tài)(New):當線程對象對創(chuàng)建后,即進入了新建狀態(tài),如:Thread t = new MyThread();
就緒狀態(tài)(Runnable):當調用線程對象的start()方法(t.start();),線程即進入就緒狀態(tài)。處于就緒狀態(tài)的線程,只是說明此線程已經做好了準備,隨時等待CPU調度執(zhí)行,并不是說執(zhí)行了t.start()此線程立即就會執(zhí)行;
運行狀態(tài)(Running):當CPU開始調度處于就緒狀態(tài)的線程時,此時線程才得以真正執(zhí)行,即進入到運行狀態(tài)。注:就 ? ? 緒狀態(tài)是進入到運行狀態(tài)的唯一入口,也就是說,線程要想進入運行狀態(tài)執(zhí)行,首先必須處于就緒狀態(tài)中;
阻塞狀態(tài)(Blocked):處于運行狀態(tài)中的線程由于某種原因,暫時放棄對CPU的使用權,停止執(zhí)行,此時進入阻塞狀態(tài),直到其進入到就緒狀態(tài),才 有機會再次被CPU調用以進入到運行狀態(tài)。根據阻塞產生的原因不同,阻塞狀態(tài)又可以分為三種:
1.等待阻塞:運行狀態(tài)中的線程執(zhí)行wait()方法,使本線程進入到等待阻塞狀態(tài);
2.同步阻塞 -- 線程在獲取synchronized同步鎖失敗(因為鎖被其它線程所占用),它會進入同步阻塞狀態(tài);
3.其他阻塞 -- 通過調用線程的sleep()或join()或發(fā)出了I/O請求時,線程會進入到阻塞狀態(tài)。當sleep()狀態(tài)超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入就緒狀態(tài)。
死亡狀態(tài)(Dead):線程執(zhí)行完了或者因異常退出了run()方法,該線程結束生命周期。
關鍵字:
yield:該線程讓出CPU,進入就緒狀態(tài)
join:該子線程優(yōu)先執(zhí)行,相當于方法調用,父線程進入IO阻塞狀態(tài)
sleep:該線程讓出CPU,進入IO阻塞狀態(tài),不釋放對象鎖
wait:同步鎖下進行使用,該線程進入阻塞狀態(tài),釋放對象鎖
notify:喚醒wait下的線程,進入同步阻塞狀態(tài)
synchronized:同步鎖,未獲得鎖的線程進入同步阻塞狀態(tài)
(五),多線程同步(Thread Synchronized)
線程同步即保證某個線程訪問某個共享資源時,其他的線程需要wait,即有順序性
(六),多線程案例
1,線程死鎖案例:
/*死鎖:
線程1:synchronized(o1) { Thread.sleep() synchronized(o2) }
線程2:synchronized(o2) { Thread.sleep() synchronized(o1) }
首先線程1執(zhí)行,對o1加同步鎖,其他線程無法訪問,
然后線程1睡眠,讓出cpu,線程2執(zhí)行,鎖住o2
線程1睡眠結束,繼續(xù)執(zhí)行,要對o2加同步鎖,但被線程2占據,所以上不了鎖,
處于等待獲得o2同步鎖的狀態(tài),且線程1不能結束,釋放不了o1對象。
線程2睡眠結束,繼續(xù)執(zhí)行,要對o1加同步鎖,但被線程1占據,所以上不了鎖,
處于等待獲得o1同步鎖的狀態(tài),且線程2不能結束,故釋放不了o2
故處于死鎖狀態(tài)。
死鎖經典問題:哲學家問題
方法:加粗鎖定對象*/
public class DeadThread implementsRunnable {private int flag=0;static Object object=new Object();//類變量,只有一份,每個實例共享
static Object object1=new Object();// public voidrun(){if (flag==0){synchronized (object) {//釋放object同步鎖,需要等object1鎖釋放,
System.out.println(flag);try{
Thread.sleep(40);
}catch(InterruptedException e) {
e.printStackTrace();
}synchronized(object1) {//System.out.println(flag);
}
}
}if (flag==1){synchronized (object1) {//釋放object1同步鎖,需要等object鎖釋放.兩個線程互相等待中
System.out.println(flag);try{
Thread.sleep(400);
}catch(InterruptedException e) {
e.printStackTrace();
}synchronized(object) {//System.out.println(flag);
}
}
}
}public static voidmain(String[] args) {
DeadThread deadThread=newDeadThread();
DeadThread deadThread1=newDeadThread();
deadThread.flag=0;
deadThread.flag=1;
Thread thread=newThread(deadThread);
Thread thread1=newThread(deadThread1);
thread.start();
thread1.start();
}
}
2,多線程多態(tài):
public classThreadTest {public static voidmain(String[] args) {for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+ " " +i);if (i == 30) {
Runnable myRunnable= newMyRunnable();
Thread thread= new MyThread(myRunnable);//輸出的是MyThread中的Run方法,多態(tài)的體現
Thread thread1=new Thread(myRunnalbe);//輸出myRunnable中run方法。
thread1.start();
thread.start();
}
}
}
}class MyRunnable implementsRunnable {private int i = 0;
@Overridepublic voidrun() {
System.out.println("in MyRunnable run");for (i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+ " " +i);
}
}
}class MyThread extendsThread {private int i = 0;publicMyThread(Runnable runnable){super(runnable);
}
@Overridepublic voidrun() {
System.out.println("in MyThread run");for (i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+ " " +i);
}
}
}
3,生產者消費者模型:
public classProducerConsumer {public static voidmain(String[] args) {
SycnStack ss=newSycnStack();
Runnable producer=newProducer(ss);
Runnable consumer=newConsumer(ss);new Thread(producer,"p1").start();/*new Thread(producer,"p2").start();
new Thread(producer,"p3").start();
new Thread(producer,"p4").start();
new Thread(producer,"p5").start();*/
new Thread(consumer,"c1").start();
}
}classWoTo{intid;
WoTo(intid){this.id=id;
}
@OverridepublicString toString() {return "WOTO"+":"+id;
}
}classSycnStack{
WoTo[] wotoArr=new WoTo[6];int index=0;public synchronized voidpush(WoTo woto){while (index==6){//wotoArr.length==6,當stack中滿6個時,生產停止,需要消費者消費并notify生產者繼續(xù)生產
try{
System.out.println("full");//發(fā)生wait后,如果沒有notify喚醒寫在wait的方法不執(zhí)行。
this.wait();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
wotoArr[index]=woto;
index+=1;this.notifyAll();//生產往后通知消費者,主要是喚醒消費者來消費,如果多線程也會喚醒生產者,但喚醒后任然可能會進入wait中
}public synchronizedWoTo pop(){while (index==0){try{
System.out.println("null");this.wait();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
index-=1;this.notifyAll();//消費完后通知生產者,喚醒生產者來生產,注釋掉會進入死鎖狀態(tài)即,消費者等生產者生產,而生產者在wait中。
returnwotoArr[index];
}
}class Producer implementsRunnable{
SycnStack ss=null;
Producer(SycnStack ss){this.ss=ss;
}
@Overridepublic voidrun() {for (int i=0;i<20;i+=1){//一個線程最多生產20個饅頭
WoTo woto=newWoTo(i);
ss.push(woto);try{
Thread.sleep(200);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":produce:"+woto);
}
}
}class Consumer implementsRunnable{
SycnStack ss=null;
Consumer(SycnStack ss){this.ss=ss;
}
@Overridepublic voidrun() {for(int i=0;i<20;i+=1){//一個消費者最多消費20個
WoTo woto=ss.pop();try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":consuemer:"+woto);
}
}
}
4,筆試題1:
public class SyncThread1 implementsRunnable {int num=100;/*m1()和m2()都加了同步鎖,執(zhí)行流程顯示調用run方法中的m1(),對num加同步鎖,然后讓出cpu,開始main線程
調用m2方法,不能訪問不能修改num,結束然后,輸出num,然后讓出cpu,繼續(xù)執(zhí)行m1()方法。sleep并不代表結束就能馬上運行,處于就緒狀態(tài)
需搶占*/
synchronized voidm1(){
num=1000;try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("num"+num);
}synchronized voidm2(){try{
Thread.sleep(500);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println(num);
num=2000;//System.out.println(num);
}public voidrun(){
m1();
}public static voidmain(String[] args) {
SyncThread1 syncThread1=newSyncThread1();
Thread thread=newThread(syncThread1);
thread.start();//新開的線程,不和main線程共線程
syncThread1.m2();//在main線程中,因為m2()加了同步鎖,即對num加鎖了,m2無法對num修改,即不執(zhí)行,直接執(zhí)行下面這個輸出
System.out.println(syncThread1.num);//main線程要等syncThread1.m2()執(zhí)行完才執(zhí)行
}
}
5,哲學家問題:
/*問題描述:一圓桌前坐著5位哲學家,兩個人中間有一只筷子,桌子中央有面條。哲學家思考問題,
當餓了的時候拿起左右兩只筷子吃飯,必須拿到兩只筷子才能吃飯。上述問題會產生死鎖的情況,
當5個哲學家都拿起自己右手邊的筷子,準備拿左手邊的筷子時產生死鎖現象。
解決辦法:
1、添加一個服務生,只有當經過服務生同意之后才能拿筷子,服務生負責避免死鎖發(fā)生。
2、每個哲學家必須確定自己左右手的筷子都可用的時候,才能同時拿起兩只筷子進餐,吃完之后同時放下兩只筷子。
代碼實現:實現第2種方案*/
public classPhilosopherDemo {public static voidmain(String[] args) {
Fork fork=newFork();//五個philosopher都指向同一個fork,所以此時相當于成員變量被多個線程共享了
Philosopher philosopher=new Philosopher(fork,0);
Philosopher philosopher1=new Philosopher(fork,1);
Philosopher philosopher2=new Philosopher(fork,2);
Philosopher philosopher3=new Philosopher(fork,3);
Philosopher philosopher4=new Philosopher(fork,4);newThread(philosopher).start();newThread(philosopher1).start();newThread(philosopher2).start();newThread(philosopher3).start();newThread(philosopher4).start();
}
}class Philosopher implementsRunnable{
Fork fork=null;intid;
Philosopher(Fork fork,intid){this.fork=fork;this.id=id;
}
@Overridepublic voidrun() {while(true){
think();
fork.getFork(this);
eat();
fork.offFork(this);
}
}public voidthink(){try{
System.out.println(id+"in thinking");
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}public voideat(){try{
System.out.println(id+"in eating");
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}classFork{boolean[] fork={false,false,false,false,false};//模擬五把叉
public synchronized voidgetFork(Philosopher p){while(fork[p.id]||fork[(p.id+1)%5]){
System.out.println("p:"+p.id+"waiting");try{
wait();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
fork[p.id]=true;
fork[(p.id+1)%5]=true;
System.out.println("p:"+p.id+"getFork");
}public synchronized voidoffFork(Philosopher p){
fork[p.id]=false;
fork[(p.id+1)%5]=false;
System.out.println("p:"+p.id+"offFork");this.notifyAll();
}
}
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的java多线程多态_Java学习之多线程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle元数据到ods,将元数据存储
- 下一篇: java美元兑换,(Java实现) 美元