欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一篇文章帶你Java多線程入門

 更新時間:2022年01月18日 17:15:08   作者:Zlxc_  
這篇文章主要為大家介紹了Java多線程入門,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

多線程的四種創(chuàng)建方式

1.繼承Thread類

 /*
 * 多線程的創(chuàng)建,方式一:繼承Thread類
 * 1.創(chuàng)建一個繼承于Thread類的子類
 * 2,重寫Thread類的run()  將線程操作寫在run方法中
 * 3.創(chuàng)建Thread類的子類的對象
 * 4.通過對象調(diào)用start()
 */
//創(chuàng)建一個繼承于Thread類的子類
public class MThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i%2==0)
                System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}
public class Threadtest {
	public static void main(String[] args) {
		//3.創(chuàng)建Thread類的子類的對象
		MThread t1=new MThread();
		//4.通過此對象調(diào)用start()
		t1.start();		//start方法來實現(xiàn)啟動線程,并調(diào)用run方法,從而真正實現(xiàn)了多線程。同時run方法它只是一個普通的函數(shù)方法,不需要線程調(diào)用start方法也可以調(diào)用它.

		
	}
}

2.實現(xiàn)Runnable接口

 /*
	1.創(chuàng)建一個實現(xiàn)了Runnable接口
    2.實現(xiàn)類去實現(xiàn)Runable接口的類
    3.創(chuàng)建實現(xiàn)類的對象
    4.將此對象作為參數(shù)傳遞到Thread類的構造器中,創(chuàng)建Thread類的對象
    5.通過Thread類的對象調(diào)用start()
  */
class  window implements Runnable{
	private int ticket =100;
	public void run() {
		while(true) {
			if(ticket >0) {
				System.out.println(Thread.currentThread().getName()+"賣票,票號為:"+ticket);
				ticket--;
			}else
				break;
			
		}
	}
}
public class RunnableTest {
	public static void main(String[] args) {
		window w=new window();
		//三個線程用的同一個window,都執(zhí)行同一個window的run,因此在設置票的數(shù)量時不需要設置為static
		Thread t1=new Thread(w);
		Thread t2=new Thread(w);
		Thread t3=new Thread(w);
		t1.setName("窗口一");
		t2.setName("窗口二");
		t3.setName("窗口三");
		t1.start();
		t2.start();
		t3.start();
		
	}
}

3.實現(xiàn)Callable接口

/*
 * 創(chuàng)建線程方式三  實現(xiàn)Callable接口
 * 實現(xiàn)Callable接口的方式強于實現(xiàn)Runnable接口的方式
 *1.call()可以有返回值。
 *2.call()可以拋出異常。
 *3.callable支持泛型。
 */

//1.創(chuàng)建一個實現(xiàn)Callable的實現(xiàn)類
class NumThread implements Callable{
	//2.實現(xiàn)call方法,將此線程需要執(zhí)行的操作聲明在call()方法中
	public Object call() throws Exception{
		int sum=0;
		for(int i=0;i<=100;i++) {
			if(i%2==0) {
				System.out.println(i);
				sum+=i;
			}
		}
		return sum;
	}
}
public class CallableWay {
	public static void main(String[] args) {
		//3.創(chuàng)建Callable接口實現(xiàn)類的對象
		NumThread numThread =new NumThread();
		//4.將此Callable接口實現(xiàn)類的對象作為傳遞到FutureTask構造器中,創(chuàng)建FutureTask對象
		FutureTask futureTask =new FutureTask(numThread);
		//5.將FutureTask的對象作為參數(shù)傳遞到Thread類的構造器中,創(chuàng)建Thread對象,并調(diào)用start()方法
		new Thread(futureTask).start();
		try {
			//6.獲取Callable中call()的返回值
			//get()返回值即為FutureTask構造參數(shù)Callable實現(xiàn)類重寫的call()的返回值
			Object sum = futureTask.get();
			System.out.println("總和為:"+sum);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
}

4.使用線程池

/*
 * 創(chuàng)建線程的方式四:使用線程池
 * 好處:
 * 1.提高響應速度(提高了創(chuàng)建新線程的時間)
 * 2.降低資源的消耗(重復利用線程池中線程,不需要每次都創(chuàng)建)
 * 3.便于線程管理
 */
class NumberThread implements Runnable{
		public void run() {	
			for(int i=0;i<=100;i++) {
				if(i%2==0) {
					System.out.println(Thread.currentThread().getName()+":"+i);
				}
			}
		}
}
public class Thread4 {
	public static void main(String[] args) {
		//1.提供指定線程數(shù)量的線程池
		ExecutorService service =Executors.newScheduledThreadPool(10);
		//2.執(zhí)行指定的線程的操作,需要提供實現(xiàn)Runnable接口或Callable接口實現(xiàn)類的對象
		service.execute(new NumberThread()); //適用于Runnable
		//service.submit(); //適用于Callable
		//3.關閉線程池
		service.shutdown();
	}

}

線程的優(yōu)先級

MAX_PRIORITY:10

MIN_PRIORITY:1

NORM_PRIORITY:5 —>默認優(yōu)先級

如何獲取和設置當前線程優(yōu)先級:

getpriority()		//獲取線程的優(yōu)先級
setpriority(int p)		//設置線程的優(yōu)先級

說明:高優(yōu)先級的線程要搶占低優(yōu)先級線程cpu的執(zhí)行權。但是只是從概率上來講,高優(yōu)先級的線程高概率的情況下被執(zhí)行,并不意味著只有高優(yōu)先級的線程執(zhí)行完后,低優(yōu)先級的線程才執(zhí)行。

測試Thread中常用的方法

1.star():啟動當前線程;調(diào)用當前線程的run()
2.run():通常需要重寫Thread類中的此方法,將創(chuàng)建的線程要執(zhí)行的操作聲明在此方法中
3.currentThread():靜態(tài)方法,返回執(zhí)行當前代碼的線程
4.getName():獲取當前線程的名字
5.setName():設置當前線程的名字
6.yield():釋放當前線程cpu的執(zhí)行權,各個線程重新“競爭”7.join():在線程a中調(diào)用線程b的join(),此時線程a就進入阻塞狀態(tài),直到線程b完全執(zhí)行完之后,線程a才結束阻塞狀態(tài)
8.stop():已過時。當執(zhí)行此方法時,強制結束當前線程
9.sleep(long millitime):讓當前線程“睡眠”指定millitime毫秒。在指定的時間內(nèi),當前線程是處于阻塞狀態(tài)
10.isAlive():判斷當前線程是否存活

線程的生命周期

在這里插入圖片描述

多線程的同步控制

1.同步代碼塊

synchronized(同步監(jiān)視器){
 	// 需要被同步的代碼
 }

下面展示實現(xiàn)Runnable接口的情況。

class TicketWindow implements Runnable {
    private int ticket = 100;
    private Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (obj) {		
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + " 賣出第 " + ticket + " 張票");
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}

public class ThreadSync {
    public static void main(String[] args) {
        TicketWindow ticketWindow = new TicketWindow();

        Thread thread1 = new Thread(ticketWindow);
        Thread thread2 = new Thread(ticketWindow);
        Thread thread3 = new Thread(ticketWindow);

        thread1.setName("售票窗口1");
        thread2.setName("售票窗口2");
        thread3.setName("售票窗口3");

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

下面展示繼承Thread類的情況。

class TicketWindow1 extends Thread {    private static int ticket = 100;    private static Object obj = new Object();    @Override    public void run() {        while (true) {            synchronized (obj) {                if (ticket > 0) {                    try {                        Thread.sleep(100);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println(Thread.currentThread().getName() + " 賣出第 " + ticket + " 張票");                    ticket--;                } else {                    break;                }            }        }    }}public class ThreadSync1 {    public static void main(String[] args) {        Thread thread1 = new TicketWindow1();        Thread thread2 = new TicketWindow1();        Thread thread3 = new TicketWindow1();        thread1.setName("售票窗口1");        thread2.setName("售票窗口2");        thread3.setName("售票窗口3");        thread1.start();        thread2.start();        thread3.start();    }}class TicketWindow1 extends Thread {
    private static int ticket = 100;
    private static Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (obj) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + " 賣出第 " + ticket + " 張票");
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}

public class ThreadSync1 {
    public static void main(String[] args) {
        Thread thread1 = new TicketWindow1();
        Thread thread2 = new TicketWindow1();
        Thread thread3 = new TicketWindow1();

        thread1.setName("售票窗口1");
        thread2.setName("售票窗口2");
        thread3.setName("售票窗口3");

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

對比二者不同二者不同在于synchronized(同步監(jiān)視器)中的同步監(jiān)視器,

實現(xiàn)Runnable接口的情況下,同步監(jiān)視器不需要用static,因為Runnable接口的實現(xiàn)類只被創(chuàng)建一次,三個線程的同步監(jiān)視器是同一個。而繼承Thread類的情況下,同步監(jiān)視器如不聲明為static則被聲明了三次,三個線程的同步監(jiān)視器不是同一。

2.同步方法

訪問修飾符 synchronized 返回值 方法名(參數(shù)列表) {
	// 同步代碼塊
}

下面展示實現(xiàn)Runnable接口的情況。

class TicketWindow implements Runnable {
    private int ticket = 100;

    @Override
    public void run() {
        while (ticket > 0) {
            sellTicket();
        }
    }

    public synchronized void sellTicket() {
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + " 賣出第 " + ticket + " 張票");
            ticket--;
        }
    }
}

下面展示繼承Thread類的情況。

class TicketWindow1 extends Thread {
    private static int ticket = 100;

    @Override
    public void run() {
        while (ticket > 0) {
            sellTicket();
        }
    }

    /**
     * 通過繼承Thread類實現(xiàn)的多線程,同步方法必須為靜態(tài)方法,因為非靜態(tài)的同步方法,同步監(jiān)視器為this,
     *         Thread thread1 = new TicketWindow1();
     *         Thread thread2 = new TicketWindow1();
     *         Thread thread3 = new TicketWindow1();
     * 而上述的this不唯一,因此無法實現(xiàn)對共享資源的互斥訪問。
     */
    public static synchronized void sellTicket() {
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + " 賣出第 " + ticket + " 張票");
            ticket--;
        }
    }
}

3.同步鎖

// 1 獲得一個鎖
Lock lock = new ReentrantLock();

// 2 加鎖
lock.lock();
// 同步代碼塊

// 3 解鎖
lock.unlock();

下面展示代碼實現(xiàn)。

class TicketWindowLock implements Runnable {
    private int ticket = 100;
    // 1 獲得一個鎖
    private Lock lock = new ReentrantLock();
    /**
     * private ReentrantLock lock = new ReentrantLock(true);
     * 帶參數(shù)的構造方法:ReentrantLock(boolean fair); ==> 公平鎖
     *      所謂公平鎖:假設現(xiàn)在三個賣票線程按 1、2、3 順序先后到達并爭取鎖,但是窗口1獲得了鎖并賣票,
     *      窗口2、3等待,等窗口1釋放鎖后,窗口2、3再按順序獲得鎖并賣票,保證按照先到先得的順序獲得鎖,
     *      以此保證公平性。
     *
     *      若是使用無參構造方法獲得鎖,則不保證公平性。同樣的,三個賣票線程按 1、2、3 順序先后到達并
     *      爭取鎖,但是窗口1獲得了鎖并賣票,窗口2、3等待,窗口1釋放鎖后,有可能再次獲得鎖并賣票,窗
     *      口2、3仍然等待,不保證公平性。
     */

    @Override
    public void run() {
        while (true) {

            try {
                // 2 上鎖
                lock.lock();

                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + " 賣出第 " + ticket + " 張票");
                    ticket--;
                } else {
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 3 解鎖。使用 try catch finally,將解鎖操作放在finally語句塊中,保證鎖一定會被釋放
                lock.unlock();
            }
        }
    }
}

synchronized與lock鎖有何異同

  • 相同:二者都是用來解決線程安全問題
  • 不同:synchronized機制在執(zhí)行完相應的同步代碼以后,自動的釋放同步監(jiān)視器,lock需要手動的打開釋放。

線程通信

wait/notify模式

涉及到的三個方法

1.wait():一旦執(zhí)行此方法,當前線程就會進入阻塞狀態(tài),并且釋放同步監(jiān)視器。

2.notify():一旦執(zhí)行此方法,就會喚醒被wait的一個線程,如果有多個線程被wait,就優(yōu)先喚醒高優(yōu)先級的線程

3.notifyAll():一旦執(zhí)行此方法,所有的線程都會被喚醒

說明上述三個方法都必須使用在同步代碼塊或同步方法中的同步監(jiān)視器中,否則會出現(xiàn)異常

上述三個方法都是定義在Object類中的。

sleep和wait的異同

相同點:一旦執(zhí)行方法,都可以使得當前的線程進入阻塞狀態(tài)。

不同點:

1)倆個方法聲明的位置不同:Thread類中聲明sleep(),Object類中聲明wait()

2)調(diào)用的要求不同:sleep可以在任何場景下調(diào)用,而wait只能在同步代碼塊或者同步方法的同步監(jiān)視器中

3)關于是否釋放同步監(jiān)視器:如果倆個方法都使用在同步代碼塊或同步方法中,sleep()不釋放,而wait()釋放。

總結

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內(nèi)容!

相關文章

最新評論