線程安全問(wèn)題的解決辦法
線程 安全問(wèn)題的解決方案:sun提供了線程同步機(jī)制讓我們解決這類問(wèn)題的液南。
java線程同步機(jī)制的方式:
方式一:同步代碼塊
同步代碼塊的格式:
synchronized(鎖對(duì)象){
需要被同步的代碼...
}
同步代碼塊要注意事項(xiàng):
1. 任意的一個(gè)對(duì)象都可以做為鎖對(duì)象。
2. 在同步代碼塊中調(diào)用了sleep方法并不是釋放鎖對(duì)象的惑芭。
3. 只有真正存在線程安全問(wèn)題的時(shí)候才使用同步代碼塊涌萤,否則會(huì)降低效率的淹遵。
4. 多線程操作的鎖 對(duì)象必須 是唯一共享 的。否則無(wú)效负溪。
class SaleTicket extends Thread{
static int num = 50;//票數(shù) 非靜態(tài)的成員變量,非靜態(tài)的成員變量數(shù)據(jù)是在每個(gè)對(duì)象中都會(huì)維護(hù)一份數(shù)據(jù)的透揣。
static Object o = new Object();
public SaleTicket(String name) {
super(name);
}
@Override
public void run() {
while(true){
//同步代碼塊
synchronized ("鎖") {//任意的一個(gè)對(duì)象都可以做為鎖對(duì)象。對(duì)象為Static川抡,但String特殊淌实,因?yàn)樽址褪窃谧址A砍刂小?
if(num>0){
System.out.println(Thread.currentThread().getName()+"售出了第"+num+"號(hào)票");
try {
Thread.sleep(100);//在同步代碼塊中調(diào)用了sleep方法并不是釋放鎖對(duì)象的。
} catch (InterruptedException e) {
e.printStackTrace();
}
num--;
}else{
System.out.println("售罄了..");
break;
}
}
}
}
}
public class Thread_02 {
public static void main(String[] args) {
String s =new String("abc");
String str1 = "abc";
System.out.println(str1 ==s);
//創(chuàng)建三個(gè)線程對(duì)象猖腕,模擬三個(gè)窗口
SaleTicket thread1 = new SaleTicket("窗口1");
SaleTicket thread2 = new SaleTicket("窗口2");
SaleTicket thread3 = new SaleTicket("窗口3");
//開(kāi)啟線程售票
thread1.start();
thread2.start();
thread3.start();
}
}
方式二:同步函數(shù)
同步函數(shù)就是使用synchronized修飾一個(gè)函數(shù)。
同步函數(shù)要注意的事項(xiàng) :
1. 如果是一個(gè)非靜態(tài)的同步函數(shù)的鎖 對(duì)象是this對(duì)象(ps:這樣會(huì)存在鎖不住的情況恨闪,因?yàn)閭z個(gè)對(duì)象調(diào)用同一個(gè)文件倘感,就會(huì)出現(xiàn)倆個(gè)鎖),如果是靜態(tài)的同步函數(shù)的鎖 對(duì)象是當(dāng)前函數(shù)所屬的類的字節(jié)碼文件(class對(duì)象)咙咽。
2. 同步函數(shù)的鎖對(duì)象是固定的老玛,不能由你來(lái)指定 的。
推薦使用: 同步代碼塊钧敞。
原因:
1. 同步代碼塊的鎖對(duì)象可以由我們隨意指定蜡豹,方便控制。同步函數(shù)的鎖對(duì)象是固定 的溉苛,不能由我們來(lái)指定镜廉。
2. 同步代碼塊可以很方便控制需要被同步代碼的范圍,同步函數(shù)必須是整個(gè)函數(shù) 的所有代碼都被同步了愚战。
class BankThread extends Thread{
static int count = 5000;
public BankThread(String name){
super(name);
}
@Override //
public void run() {
getMoney();//這樣也鎖定住娇唯,但是會(huì)造成只能一個(gè)人取完全部的錢齐遵,因?yàn)橹挥醒h(huán)結(jié)束,才會(huì)釋放鎖
}
//靜態(tài)的函數(shù)---->函數(shù)所屬 的類的字節(jié)碼文件對(duì)象--->BankThread.class 唯一的塔插。
public static synchronized void getMoney(){
while(true){
if(count>0){
System.out.println(Thread.currentThread().getName()+"取走了1000塊,還剩余"+(count-1000)+"元");
count= count - 1000;
}else{
System.out.println("取光了...");
break;
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
//創(chuàng)建兩個(gè)線程對(duì)象
BankThread thread1 = new BankThread("老公");
BankThread thread2 = new BankThread("老婆");
//調(diào)用start方法開(kāi)啟線程取錢
thread1.start();
thread2.start();
}
}
出現(xiàn)線程安全問(wèn)題的根本原因:
1. 存在兩個(gè)或者兩個(gè)以上 的線程對(duì)象,而且線程之間共享著一個(gè)資源梗摇。
2. 有多個(gè)語(yǔ)句操作了共享資源。
線程的死鎖
/*
* java 中同步機(jī)制解決了線程安全問(wèn)題想许,但是同時(shí)引發(fā)死鎖現(xiàn)象
*
* 死鎖現(xiàn)象:就是 倆個(gè)或者倆個(gè)以上線程伶授,共同調(diào)用倆個(gè)或者以上的資源,發(fā)生共同等待的狀態(tài)
*
* 死鎖現(xiàn)象的出現(xiàn)的根本原因:
* 1.存在倆個(gè)或者倆個(gè)以上的線程
* 2.存在倆個(gè)或者倆個(gè)以上的共享資源
*
* 死鎖現(xiàn)象的解決方案:沒(méi)有方案流纹,只能盡量避免發(fā)生而已
*/
class DeadLock extends Thread{
public DeadLock(String name){
super(name);
}
public void run(){
if("張三".equals(Thread.currentThread().getName())){
synchronized ("遙控器") {
System.out.println("張三拿到了遙控器糜烹,準(zhǔn)備去拿電池!捧颅!");
synchronized ("電池") {
System.out.println("張三拿到了遙控器和電池景图,開(kāi)始吹空調(diào)");
}
}
}else if("李四".equals(this.getName())){
synchronized ("電池") {
System.out.println("李四拿到了電池,準(zhǔn)備去那遙控器");
synchronized ("遙控器") {
System.out.println("李四拿到了遙控器和電池碉哑,開(kāi)始吹空調(diào)");
}
}
}
}
}
public class Thread_04 {
public static void main(String[] args) {
DeadLock l1=new DeadLock("張三");
DeadLock l2=new DeadLock("李四");
l1.start();
l2.start();
}
}