1. 程式人生 > >多執行緒之同步鎖 加鎖和執行緒停止

多執行緒之同步鎖 加鎖和執行緒停止

一.同步程式碼塊(同步鎖)
寫法:
synchronized(鎖){
上鎖的程式碼
}
當執行緒進入同步程式碼塊 會把鎖拿走 執行程式碼塊中的程式碼
程式碼執行完畢後 會把鎖還回去
如果執行緒遇到同步程式碼塊 發現沒有鎖 將進入等待(有鎖才可進)

鎖的注意:保證所有執行緒使用的是同一個鎖 鎖可以使用任意一個物件(同一個物件就行)
public class Demo01 {
public static void main(String[] args) {
//利用介面的實現類 建立三個執行緒出來
Tickets tickets=new Tickets();
Thread t1=new Thread(tickets);
Thread t2=new Thread(tickets);
Thread t3=new Thread(tickets);
t1.start();
t2.start();
t3.start();
}
}
class Tickets implements Runnable {
private int tickets = 30;
// 宣告鎖的物件
private final Object obj = new Object();
public void run() {
// 利用迴圈
while (true) {
synchronized (obj) {
// 休眠
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 判斷
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "

" + tickets);
tickets–;
} else {
break;
}
}
//讓執行緒讓出cpu的執行資源
Thread.yield();
}
}
}
二.加鎖和釋放鎖
lock();加鎖方法
unlock();釋放鎖方法
保證出現異常時也能把鎖關閉
寫法:lock();
try{
加鎖的程式碼
}finaly{
釋放鎖
unlock();
}
public class Demo2 {
public static void main(String[] args) {
Tickets2 tickets=new Tickets2();
//建立三個執行緒
Thread t1=new Thread(tickets);
Thread t2=new Thread(tickets);
Thread t3=new Thread(tickets);
t1.start();
t2.start();
t3.start();
}
}
//利用介面方法
class Tickets2 implements Runnable {
private int tickets = 10;
// 宣告鎖的物件
private final Object obj = new Object();
//宣告lock鎖
//引數 :true 可以讓執行緒儘量公平加入鎖
private final ReentrantLock lock =new ReentrantLock(true);
public void run() {
// 利用迴圈
while (true) {
//使用lock鎖
lock.lock();
try {
if (tickets>0) { System.out.println(Thread.currentThread().getName()+"
"+tickets);
tickets–;
}else {
break;
}
} finally {
//釋放鎖
lock.unlock();
}
Thread.yield();
}
}
}
三.死鎖
前提:至少是兩個執行緒 鎖的巢狀(同步程式碼塊的巢狀)
public class Demo03 {
public static void main(String[] args) {
test1Thread test=new test1Thread();
Thread t1=new Thread(test);
Thread t2=new Thread(test);
t1.start();
t2.start();
}
}
//宣告鎖
class LockA{
//私有化構造方法
private LockA() {
}
//建立鎖物件
public static final LockA A_=new LockA();
}
class LockB{
//私有化構造方法
private LockB() {
}
//建立鎖物件
public static final LockB B_=new LockB();
}
//執行緒
class test1Thread implements Runnable{
//利用標記來控制先A->B或先B->A
boolean isture=false;
public void run() {
//利用死迴圈
while (true) {
//讓兩個執行緒不斷的先進A鎖再進B鎖 下一次從B進A鎖
if (!isture) {
//先進A再進B(同步程式碼塊巢狀)
synchronized (LockA.A_) {
System.out.println(“if中的A鎖”);
synchronized (LockB.B_) {
System.out.println(“if中的B鎖”);
}
}
} else {
//下次從B進A
synchronized (LockB.B_) {
System.out.println(“else中的B鎖”);
synchronized (LockA.A_) {
System.out.println(“else中的A鎖”);
}
}
}
//改變一下標記
isture=!isture;
}
}
}
四.執行緒停止
呼叫Stop方法 已經過時 不推薦使用
interrupt()方法 不能中斷執行緒 中斷狀態將被設定
interrupt()方法 1.可以改變中斷狀態 是個布林值 初值false->true
2.當此執行緒中 使用sleep wait join方法時 會丟擲中斷異常 中斷狀態將被清除 此時interrupted()的值還是false
直接使用標記停止執行緒
public class Demo04 {
public static void main(String[] args) {
interruptedRunnable iRunnable=new interruptedRunnable();
Thread t=new Thread(iRunnable);
t.start();
//休眠幾秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//中斷執行緒
//t.interrupt
();
//利用標記停止執行緒
iRunnable.istrue=true;
System.out.println("執行緒中斷
**");
//主執行緒繼續執行
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(“主執行緒結束”);
}
}
class interruptedRunnable implements Runnable{
//宣告一個標記 控制執行緒的停止
public boolean istrue=false;
public void run() {
while (!istrue) {
/* long timeMillis = System.currentTimeMillis();
while (System.currentTimeMillis()-timeMillis<1000) {

	}   */
	try {
		//丟擲中斷異常
		//中斷狀態被清除指的是從休眠狀態-->執行狀態(或者受阻塞)
		Thread.sleep(1000);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	System.out.println(Thread.currentThread().getName()+"run");
}	
}

}