單例模式
- 之前有一個博客簡述了單例模式,這裏就不具體介紹了
- 單例模式的實現方式:懶漢式和餓漢式
- 其中,懶漢式是線程不安全的,當有多條線程同時訪問單例對象時,則會出現多線程臨界資源問題
多線程下的懶漢式
package waking.test.xcms;
import java.util.HashSet;
public class Demo01 {
static HashSet<Kind> hs = new HashSet<Kind>();
static Runnable r = new Runnable() {
@Override
public void run() {
Kind kind = Kind.getKindInstance();
hs.add(kind);
}
};
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
Thread t = new Thread(r);
t.start();
}
System.out.println(hs);
}
}
class Kind {
private static Kind kind = null;
private Kind() {
}
public static Kind getKindInstance() {
if(kind==null) {
kind = new Kind();
}
return kind;
}
}
多線程下的餓漢式
package waking.test.xcms;
import java.util.HashSet;
public class Demo02 {
static HashSet<Hungry> hs = new HashSet<Hungry>();
static Runnable r = new Runnable() {
@Override
public void run() {
Hungry h = Hungry.getHungryInstance();
hs.add(h);
}
};
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
Thread t = new Thread(r);
t.start();
}
System.out.println(hs);
}
}
class Hungry{
private static Hungry hungry = new Hungry();
private Hungry() {
}
public static Hungry getHungryInstance() {
return hungry;
}
}
生產者、消費者模式
原理
- 它描述的是有一塊緩衝區作爲倉庫,生產者可以將產品放入倉庫,消費者可以從倉庫中取走產品,解決生產者、消費者問題,我,們需要採用某種機制保護生產者和消費者的同步
- 同步的問題核心在於:如何保證同一個資源被多個線程併發訪問時的完整性,常用的方法就是加鎖,保證資源在任意時刻只被一份線程訪問
實現
- 方式一:採用wait()、notify()和notifyAll()方法
wait():當緩衝區已滿或空時,生產者、消費者線程停止自己的執行,放棄鎖,使用自己處於等待狀態,讓其他線程執行
說明:
a.是Object的方法
b.調用方式:對象.wait();
c.表示釋放、對象這個鎖標記,然後在鎖外面等待(對比sleep(),sleep()是抱着鎖休眠的)
d.等待,必須放到同步代碼中執行
notify():當生產者、消費者向緩衝區放入、取出一個產品時,向其他等待的線程發出可執行的通知,同時放棄鎖,使自己處於等待狀態
說明:
a.是object的方法
b.調用方式:對象.notify();
c.表示喚醒對象所標記外邊在等待的一個線程
notifyAll():全部喚醒
a.是objectde 方法
b.調用方式:對象.notifyAll()
c.表示喚醒對象所標記外邊等待的所有線程
package waking.test.xcms;
public class Demo03 {
static boolean shouldProduct = true;
static class Productor implements Runnable{
private Product product;
public Productor(Product product) {
this.product = product;
}
@Override
public void run() {
while(true) {
synchronized ("") {
if(shouldProduct) {
this.product.setName("waking");
System.out.println("生產者:"+Thread.currentThread().getName()+"生產了,一個"+this.product);
shouldProduct=false;
"".notifyAll();
}else {
try {
"".wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
static class Consumer implements Runnable{
private Product P;
public Consumer(Product p) {
this.P = p;
}
@Override
public void run() {
while(true) {
synchronized ("") {
if(shouldProduct) {
try {
"".wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
System.out.println("消費者:"+Thread.currentThread().getName()+"消費了,一個產品"+this.P);
shouldProduct=true;
"".notifyAll();
}
}
}
}
}
public static void main(String[] args) {
Product p = new Product();
Productor por = new Productor(p);
Thread t = new Thread(por,"A");
Thread t2 = new Thread(por,"B");
Thread t3 = new Thread(por,"C");
Thread t4 = new Thread(por,"D");
t.start();
t2.start();
t3.start();
t4.start();
Consumer c = new Consumer(p);
Thread t5 = new Thread(c,"a");
Thread t6 = new Thread(c,"b");
Thread t7 = new Thread(c,"c");
Thread t8 = new Thread(c,"d");
t5.start();
t6.start();
t7.start();
t8.start();
}
}
class Product{
private String name;
int id;
public String getName() {
id--;
return name;
}
public void setName(String name) {
this.name = name;
id++;
}
@Override
public String toString() {
return "Product [name=" + name + ", id=" + id + "]";
}
}
- 採用ReentrantLock類中的newCondition()方法結合Condition類中的await()、signal()和signalAll()方法
package waking.test.xcms;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Demo04 {
static boolean flage = true;
static ReentrantLock lock = new ReentrantLock();
static Condition c1 = lock.newCondition();
static Condition c2 = lock.newCondition();
static class Pro implements Runnable{
private S s;
public Pro(S s) {
super();
this.s = s;
}
@Override
public void run() {
while(true) {
try {
lock.lock();
if (flage) {
this.s.setName("waking");
System.out.println("生產者:" + Thread.currentThread().getName() + "生產了" + this.s);
flage = false;
c2.signalAll();
} else {
try {
c1.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
lock.unlock();
}
}
}
}
static class Con implements Runnable{
private S ss;
public Con(S ss) {
super();
this.ss = ss;
}
@Override
public void run() {
while(true) {
try {
lock.lock();
if (flage) {
try {
c2.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println("消費者:" + Thread.currentThread().getName() + "消費了" + this.ss);
flage = true;
c1.signalAll();
}
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
S s = new S();
Pro p = new Pro(s);
new Thread(p,"A").start();
new Thread(p,"B").start();
new Thread(p,"C").start();
new Thread(p,"D").start();
Con c = new Con(s);
new Thread(c, "a").start();
new Thread(c, "b").start();
new Thread(c, "c").start();
new Thread(c, "d").start();
}
}
}
class S{
private String name;
int id;
public String getName() {
id--;
return name;
}
public void setName(String name) {
this.name = name;
id++;
}
@Override
public String toString() {
return "S [name=" + name + ", id=" + id + "]";
}
}
以上是多線程下的單例模式、生產者、消費者模式的情況,感謝您的觀看