volatile 修饰的变量, 能够保证 “内存可见性”
上述过程的完整代码如下:
public class Demo14 {
//使用locker对象负责加锁,wait,notify
private static Object locker=new Object();
public static void main(String[] args) {
Thread t1=new Thread(() ->{
while(true){
synchronized (locker){
System.out.println("t1 wait开始");
try {
locker.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 wait结束");
}
}
});
t1.start();
Thread t2=new Thread(() ->{
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (locker){
System.out.println("t2 notify开始");
locker.notify();
System.out.println("t2 notify结束");
}
}
});
t2.start();
}
}
其中,我们观察到notify的开始和结束的过程是非常快的
下面介绍代码案例
****
饿汉模式
懒汉模式
类加载的时候不创建实例. 第一次使用的时候才创建实例.
因为只有使用getInstance的时候,才会new出来一个对象;而在饿汉模式下,instance被当做一个类的属性,在类的加载的时候就被创建了。
上述过程的完整代码如下:
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
//生产者消费者模型
public class Demo18 {
public static void main(String[] args) {
//建一个阻塞队列,作为交易场所
BlockingDeque<Integer> queue=new LinkedBlockingDeque<>();
//一个线程负责生产
Thread t1=new Thread(() ->{
int count=0;
while(true){
try {
queue.put(count);
System.out.println("生产的元素为:"+count);
count++;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//一个线程负责消耗
Thread t2=new Thread(() ->{
while(true){
try {
Integer n=queue.take();
System.out.println("消耗的元素为:"+n);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
}
}
阻塞队列的模拟实现
下面首先实现一般的队列
上述过程的代码如下:
class MyBlockingQueue{
//使用循环队列来表示这个阻塞队列
private String[] items=new String[1000];
//队列的头部
int head=0;
//tail:队列的尾部的下一个元素. 总的来说, 队列中有效元素的范围 [head, tail)
// 当 head 和 tail 相等(重合), 相当于空的队列.
int tail=0;
//size表示队列当前的元素个数
int size=0;
public void put(String elem){
if(size>=items.length){//队列满
return;
}
items[tail]=elem;
tail++;
if(tail>= items.length){
tail=0;
}
size++;
}
public String take(){
if(size==0){
return null;
}
String elem=items[head];
head++;
if(head>= items.length){
head=0;
}
size--;
return elem;
}
}
public class Demo19 {
public static void main(String[] args) {
MyBlockingQueue queue=new MyBlockingQueue();
queue.put("aaa");
queue.put("bbb");
queue.put("ccc");
queue.put("ddd");
String elem= queue.take();
System.out.println("elem="+elem);
elem= queue.take();
System.out.println("elem="+elem);
elem= queue.take();
System.out.println("elem="+elem);
}
}
考虑线程安全性
实现阻塞
上述实现过程的最终代码如下:
class MyBlockingQueue{
//使用循环队列来表示这个阻塞队列
private String[] items=new String[10];
//队列的头部
volatile int head=0;
//tail:队列的尾部的下一个元素. 总的来说, 队列中有效元素的范围 [head, tail)
// 当 head 和 tail 相等(重合), 相当于空的队列.
volatile int tail=0;
//size表示队列当前的元素个数
volatile int size=0;
public void put(String elem) throws InterruptedException {
synchronized (this){
while(size>=items.length){//队列满
//return;
this.wait();
}
items[tail]=elem;
tail++;
if(tail>= items.length){
tail=0;
}
size++;
this.notify();
}
}
public String take() throws InterruptedException {
synchronized (this){
while(size==0){
// return null;
this.wait();
}
String elem=items[head];
head++;
if(head>= items.length){
head=0;
}
size--;
this.notify();
return elem;
}
}
}
public class Demo19 {
public static void main(String[] args) {
/* MyBlockingQueue queue=new MyBlockingQueue();
queue.put("aaa");
queue.put("bbb");
queue.put("ccc");
queue.put("ddd");
String elem= queue.take();
System.out.println("elem="+elem);
elem= queue.take();
System.out.println("elem="+elem);
elem= queue.take();
System.out.println("elem="+elem);*/
//创建两个线程,表示生产者和消费者
MyBlockingQueue queue=new MyBlockingQueue();
Thread t1=new Thread(() ->{
int count=0;
while (true){
try {
queue.put(count + "");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生产"+count);
count++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2=new Thread(() ->{
while (true){
String elem= null;
try {
elem = queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消耗"+elem);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
}
}