1、建立線程的方法一:編程
繼承:extends Thread 重寫run()方法安全
舉個栗子🌰:bash
public class MyThread extends Thread {
public MyThread() {
//空的構造方法
}
//傳遞name表示線程名字
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (interrupted()) {
System.out.println("釋放資源!");
break;
}
System.out.println(getName()+":"+i);
}
}
}
複製代碼
MyThread t1 = new MyThread(「線程一」);
MyThread t2 = new MyThread(「線程二」);
Thread thread = new Thread();
thread.start();//啓動線程
thread.getPriority();//獲取優先級
thread.setPriority();//設置優先級(1-10)
thread .getName();//獲取線程名字
thread .setName();//設置線程名字
複製代碼
線程休眠:微信
Thread.sleep(4000);//主線程休眠四秒以後再運行
複製代碼
線程加入:多線程
t1.join();//將線程t1加入主線程
複製代碼
設置守護線程:app
t2.setDaemon(true);將t2線程設置爲守護線程(守護線程須要在線程啓動以前設置),守護線程是爲守護其餘線程而存在,若是其餘全部線程都運行完以後,只還剩下守護線程沒運行完,那麼守護線程將自動銷燬!ide
線程的中斷:ui
t1.interrupt();//手動處理線程中斷
interrupted();//將返回布爾值
複製代碼
線程的生命週期: this
2、建立線程的方法二:spa
實現Runnable接口: implement Runnable
public class RunnableThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
Thread thread = Thread.currentThread();//獲取當前線程名字
System.out.println(thread.getName()+":"+i);
}
}
}
複製代碼
該方法不能直接使用start()方法啓動線程。 須要使用Thread聲明一個對象,再將runnable對象傳入Thread對象。
RunnableThread t = new RunnableThread();
Thread t1 = new Thread(t,」線程一」);
t1.start();
Thread t2 = new Thread(t,」線程二」);
t2.start();
複製代碼
兩種建立線程方法區別: runnable方法只須要建立一個runnable對象,Thread方法須要建立多個MyThread對象。Thread方法獲取線程其餘參數更方便。兩種方法都須要重寫run()方法。
使用Runnable方法建立線程的好處:
3、建立線程的方法三:
匿名內部類: 直接在主類裏面定義一個Runnable類來實現Runnable接口裏面的run()方法。
適用於該線程在主類裏面只使用一次的狀況,不用再建立一個線程類來實現Runnable接口。
線程安全問題: 當多個線程須要同時修改同一共享數據時,產生衝突,就會出現線程安全問題。
private Object lock = new Object();//須要聲明一個對象做爲鎖
複製代碼
//加鎖
synchronized (lock) {
//須要加鎖執行的代碼
}//執行完畢,歸還鑰匙
複製代碼
也能夠直接使用同步方法:sellTicket()
public synchronized void sellTicket(){
//須要加鎖的代碼
}//至關於給這個方法加了鎖
複製代碼
同步方法不須要再聲明一個對象做爲鎖了。
private ReentrantLock lock = new ReentrantLock();
複製代碼
lock.lock();//加鎖
//須要加鎖的代碼
lock.unlock();//解鎖
複製代碼
死鎖問題的解決:
多個線程以相同的順序去取鎖,取到全部鎖以後才執行須要加鎖的代碼!
舉個栗子🌰:
public class DeadLock {
//建立兩把鎖
public static Object lock1 = new Object();
public static Object lock2 = new Object();
public static void main(String[] args) {
//啓動兩個線程
new Thread(new Thread1()).start();
new Thread(new Thread2()).start();
}
}
//匿名內部類實現Runnable建立Thread1線程
class Thread1 implements Runnable{
@Override
public void run() {
synchronized (DeadLock.lock1) {//先取第一把鎖
System.out.println("Thread1取得了第一把鎖以後要作的事情");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (DeadLock.lock2) {//再取第二把鎖
System.out.println("Thread1同時取得兩把鎖以後要作的事情");
}
}
}
}
//匿名內部類實現Runnable建立Thread2線程
class Thread2 implements Runnable{
@Override
public void run() {
synchronized (DeadLock.lock1) {//先取第一把鎖
System.out.println("Thread2取得了第二把鎖以後要作的事情");
synchronized (DeadLock.lock2) {//再取第二把鎖
System.out.println("Thread2同時取得兩把鎖以後要作的事情");
}
}
}
}
複製代碼
建立線程組:ThreadGroup
ThreadGroup tg = new ThreadGroup(「個人線程組」);
複製代碼
定時器:Timer
須要在計時器任務裏面設置任務:TimerTask
Timer timer = new Timer();//定時器
timer.schedule(new MyTimer(), 2000);//2s後啓動計時器任務
timer.schedule(new MyTimer(), 2000, 1000);//2s啓動後,隔3s後再重複執行計時器任務
timer.cancel();//取消定時器
複製代碼
舉個栗子🌰:
public class Demo_Timer {
public static void main(String[] args) {
Timer timer = new Timer();//定時器
//timer.schedule(new MyTimer(), 2000);
timer.schedule(new MyTimer(), 2000, 1000);
//timer.cancel();//取消定時器
}
}
//定時器任務(匿名內部類)
class MyTimer extends TimerTask{
@Override
public void run() {
System.out.println("定時器任務..");
}
}
複製代碼
4、綜合實例:
電影院售票問題: 說明:兩種買票方式,手機APP端和電影院窗口端同時售票,採用建立多線程的方式來解決電影票多端售出產生的衝突!
採用實現Runnable接口的方法建立線程。
一、建立AppThread類:(APP端線程類)
public class AppThread implements Runnable {
private Object lock;
public AppThread(Object lock) {
this.lock = lock;
}
@Override
public void run() {
while (MovieTicketManage.count>0) {
synchronized (lock) {
if (MovieTicketManage.count>0) {
System.out.println(Thread.currentThread().getName()+"售出了第"+MovieTicketManage.count+"張電影票..");
MovieTicketManage.count--;
}
}
try {
Thread.sleep(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
複製代碼
二、建立WindowThread類:(window端線程類)
public class WindowThread implements Runnable {
private Object lock;
public WindowThread(Object lock) {
this.lock = lock;
}
@Override
public void run() {
while (MovieTicketManage.count>0) {
synchronized (lock) {
if (MovieTicketManage.count>0) {
System.out.println(Thread.currentThread().getName()+"售出了第"+MovieTicketManage.count+"張電影票..");
MovieTicketManage.count--;
}
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
複製代碼
三、建立MovieTicketManage類:(票管理類,存儲電影票數量,爲了多線程數據的共享)
public class MovieTicketManage {
public static int count = 100;
}
複製代碼
四、建立CinemaSale主類:(電影票售票主類)
public class CinemaSale {
public static void main(String[] args) {
Object lock = new Object();
WindowThread windowThread = new WindowThread(lock);
AppThread appThread = new AppThread(lock);
new Thread(windowThread,"窗口").start();
new Thread(appThread,"APP手機").start();
}
}
複製代碼
須要建立一把相同的鎖lock,將這把鎖傳入AppThread和WindowThread線程類,保證鎖的惟一,若是在AppThread線程和WindowThread線程裏面建立鎖,那麼就是不一樣對象的鎖了。就不能保證共享數據的同步,經過定義一個成員變量lock,經過構造方法將這個鎖傳遞過來.
這樣在購買電影票的時候就不會產生線程衝突和死鎖問題了!😁
今日寄語:
歡迎關注我的微信公衆號:桃李報春