Java多線程(一):
https://blog.csdn.net/Veer_c/article/details/103842078
Java多線程(二):
https://blog.csdn.net/Veer_c/article/details/103842263
Java多線程(三):
https://blog.csdn.net/Veer_c/article/details/103842317
Java多線程(四):
https://blog.csdn.net/Veer_c/article/details/103842602
案例:利用匿名內部類,啓動多個線程,驗證單例設計模式之懶漢式所存在的缺陷,
public class SingleIntanceDemo {
//私有化構造
private SingleIntanceDemo(){}
private static SingleIntanceDemo instance = null;
public static SingleIntanceDemo getInstance(){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (instance==null) {
instance = new SingleIntanceDemo();
}
return instance;
}
}
public class Test {
public static void main(String[] args) {
//啓動第一個線程
new Thread(){
@Override
public void run() {
System.out.println(SingleIntanceDemo.getInstance());
//com.edu_12.SingleIntanceDemo@2d7fc1e7
}
}.start();
//啓動第二個線程
new Thread(){
public void run() {
System.out.println(SingleIntanceDemo.getInstance());
//com.edu_12.SingleIntanceDemo@2a8b83e3
};
}.start();
}
}
當我們利用多線程來驗證單例模式的時候,發現倆個對象的地址值不同,即不是同一個對象,我們可以利用同步方法來改進
在創建對象的方法上加上 synchronized關鍵字就可以
(9)JDK5的Lock鎖,我們之前造的所有的鎖都沒有手動釋放鎖
static Lock lock = new ReentrantLock();
上枷鎖:lock.lock();
釋放鎖:lock.unlock();
可以讓我們明確的知道在哪裏加鎖和釋放鎖。
依然寫一個賣票的案例,用lock枷鎖釋放鎖,
爲了保證我們創建的鎖一定會被釋放,用一下代碼進行改進
try{….}finally{……}
public class MyThread implements Runnable{
//定義100張票
int ticket = 100;
Object obj = new Object();
//創建一個鎖
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try{
//加上鎖,獲取鎖
lock.lock();
if (ticket>0) {
//考慮到實際的生活中,我們需要給每一個線程加入一定的延遲,模擬一下這種效果
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第:"+ticket--+"張票");
}
}finally{
//這裏面的代碼一定會被執行
//釋放鎖
lock.unlock();
}
}
}
}
public class Test {
public static void main(String[] args) {
//創建MyThread對象
MyThread mt = new MyThread();
//創建三個窗口
Thread t1 = new Thread(mt);
Thread t2 = new Thread(mt);
Thread t3 = new Thread(mt);
//給每一個窗口設置姓名
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
//開啓窗口進行售票
t1.start();
t2.start();
t3.start();
}
}
死鎖問題:
同步嵌套,鎖裏面套了一個鎖,出現同步嵌套
package com.edu_14;
public class DieThread extends Thread{
boolean flag;
//提供一個有參構造
public DieThread(boolean flag){
this.flag = flag;
}
@Override
public void run() {
if (flag) {
synchronized (MyLock.objA) {
System.out.println("if"+"objA");
synchronized (MyLock.objB) {
System.out.println("if"+"objB");
}
}
}else {
synchronized (MyLock.objB) {
System.out.println("else"+"objB");
synchronized (MyLock.objA) {
System.out.println("else"+"objA");
}
}
}
}
}
package com.edu_14;
public abstract class MyLock {
//定義兩個鎖
public static final Object objA = new Object();
public static final Object objB = new Object();
}
package com.edu_14;
public class Test {
public static void main(String[] args) {
//創建兩個線程,分別設置不同的布爾值
DieThread dt = new DieThread(true);
DieThread dt2 = new DieThread(false);
//開啓兩個線程
dt.start();
dt2.start();
}
}
線程等待和喚醒機制:waitThread,NotifyThread,MyLock,Test
鎖對象調用wait() 鎖對象調用notify()
package com.edu_15;
public abstract class MyLock {
public static final Object obj = new Object();
}
package com.edu_15;
public class WaitThread extends Thread{
@Override
public void run() {
synchronized (MyLock.obj) {
//讓等待線程處於等待狀態
try {
MyLock.obj.wait();//當線程處於等待狀態的時候,線程就不會繼續往下執行了
//線程在處於等待的時候,會釋放掉自己手中的鎖
//sleep()這個方法,在線程休息的時候會釋放鎖碼?
//答:不會
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("我被喚醒了");
}
}
package com.edu_15;
public class NotifyThread extends Thread{
@Override
public void run() {
synchronized (MyLock.obj) {
//喚醒等待線程
MyLock.obj.notify();//喚醒正在等待的線程,喚醒的等待線程的鎖對象,必須和等待線程的鎖對象一致
}
}
}
package com.edu_15;
/* (11)線程等待和喚醒機制(案例演示:waitThread,NotifyThread,MyLock,Test)
鎖對象調用wait():線程的等待
鎖對象調用notify():線程的喚醒
* 注意:
wait和sleep的區別
線程等待,在等待的同時釋放鎖,而sleep()方法在執行的過程中是不會釋放鎖的 */
public class Test {
public static void main(String[] args) {
//創建等待線程,讓等待線程處於一個等待狀態
WaitThread wt = new WaitThread();
wt.start();
//睡上5秒鐘之後喚醒等待線程
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//創建喚醒線程對象
NotifyThread nt = new NotifyThread();
nt.start();
}
}
注意:wait和sleep的區別:
線程等待,在等待的同時釋放鎖,而sleep()方法在執行的過程中是不會釋放鎖的
Java多線程(一):
https://blog.csdn.net/Veer_c/article/details/103842078
Java多線程(二):
https://blog.csdn.net/Veer_c/article/details/103842263
Java多線程(三):
https://blog.csdn.net/Veer_c/article/details/103842317
Java多線程(四):
https://blog.csdn.net/Veer_c/article/details/103842602