文章目录
1写一个线程安全的单例模式
/**
* 线程安全的单例模式:
*
* 阅读文章:http://www.cnblogs.com/xudong-bupt/p/3433643.html
*
* 更好的是采用下面的方式,既不用加锁,也能实现懒加载
*
* @author 马士兵
*/
package yxxy.c_023;
import java.util.Arrays;
public class Singleton {
private Singleton() {
System.out.println("single");
}
private static class Inner {
private static Singleton s = new Singleton();
}
public static Singleton getSingle() {
return Inner.s;
}
public static void main(String[] args) {
Thread[] ths = new Thread[200];
for(int i=0; i<ths.length; i++) {
ths[i] = new Thread(()->{
System.out.println(Singleton.getSingle());
});
}
Arrays.asList(ths).forEach(o->o.start());
}
}
2 有N张火车票,每张票都有一个编号,同时有10个窗口对外售票,请写一个模拟程序
2.1 第一个程序
/**
* 有N张火车票,每张票都有一个编号
* 同时有10个窗口对外售票
* 请写一个模拟程序
*
* 分析下面的程序可能会产生哪些问题?
* 重复销售?超量销售?
*
*
* @author 马士兵
*/
package yxxy.c_024;
import java.util.ArrayList;
import java.util.List;
public class TicketSeller1 {
static List<String> tickets = new ArrayList<>();
static {
for(int i=0; i<10000; i++) tickets.add("票编号:" + i);
}
public static void main(String[] args) {
for(int i=0; i<10; i++) {
new Thread(()->{
while(tickets.size() > 0) {
System.out.println("销售了--" + tickets.remove(0));
}
}).start();
}
}
}
剩到最后一张票时,还是有很多线程去访问,每个线程看到的都是1,都去执行。就会超量
remove不是同步的。不加锁是不行的。
2.2第二个程序:使用Vector
在这里插入代码片/**
* 有N张火车票,每张票都有一个编号
* 同时有10个窗口对外售票
* 请写一个模拟程序
*
* 分析下面的程序可能会产生哪些问题?
*
* 使用Vector或者Collections.synchronizedXXX
* 分析一下,这样能解决问题吗?
*
* @author 马士兵
*/
package yxxy.c_024;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
public class TicketSeller2 {
static Vector<String> tickets = new Vector<>();
static {
for(int i=0; i<1000; i++) tickets.add("票 编号:" + i);
}
public static void main(String[] args) {
for(int i=0; i<10; i++) {
new Thread(()->{
while(tickets.size() > 0) {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("销售了--" + tickets.remove(0));
}
}).start();
}
}
}
Vector 判断和操作分离了
在对象Vector中,remove,size是原子的,但是判断和remove是分离的。确保不了两个原子中间有错误。打断的话,问题依旧:
在判断和remove中的操作,不是原子性的。 有可能还会被其他线程打断。 出现问题。
2.3第三个程序:使用Vector,在加一个锁
锁定一个对象,放在代码块里边。相当于把判断和操作加到了一个原子里边去。
但效率不是特别高。每次卖出一张票的时候,都把整个队列锁定了。
/**
* 有N张火车票,每张票都有一个编号
* 同时有10个窗口对外售票
* 请写一个模拟程序
*
* 分析下面的程序可能会产生哪些问题?
* 重复销售?超量销售?
*
* 使用Vector或者Collections.synchronizedXXX
* 分析一下,这样能解决问题吗?
*
* 就算操作A和B都是同步的,但A和B组成的复合操作也未必是同步的,仍然需要自己进行同步
* 就像这个程序,判断size和进行remove必须是一整个的原子操作
*
* @author 马士兵
*/
package yxxy.c_024;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class TicketSeller3 {
static List<String> tickets = new LinkedList<>();
static {
for(int i=0; i<1000; i++) tickets.add("票 编号:" + i);
}
public static void main(String[] args) {
for(int i=0; i<10; i++) {
new Thread(()->{
while(true) {
synchronized(tickets) {
if(tickets.size() <= 0) break;
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("销售了--" + tickets.remove(0));
}
}
}).start();
}
}
}
2.4第四个程序:并发容器 ConcurrentQueue
/**
* 有N张火车票,每张票都有一个编号
* 同时有10个窗口对外售票
* 请写一个模拟程序
*
* 分析下面的程序可能会产生哪些问题?
* 重复销售?超量销售?
*
* 使用Vector或者Collections.synchronizedXXX
* 分析一下,这样能解决问题吗?
*
* 就算操作A和B都是同步的,但A和B组成的复合操作也未必是同步的,仍然需要自己进行同步
* 就像这个程序,判断size和进行remove必须是一整个的原子操作
*
* 使用ConcurrentQueue提高并发性
*
* @author 马士兵
*/
package yxxy.c_024;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
public class TicketSeller4 {
static Queue<String> tickets = new ConcurrentLinkedQueue<>();
static {
for(int i=0; i<1000; i++) tickets.add("票 编号:" + i);
}
public static void main(String[] args) {
for(int i=0; i<10; i++) {
new Thread(()->{
while(true) {
String s = tickets.poll();
if(s == null) break;
else System.out.println("销售了--" + s);
}
}).start();
}
}
}
创建一个队列tickets。往这个队列中放票,从尾部放,往头边取。直到取出来为空时,停止
不是加锁的实现,效率高很多。
来源:CSDN
作者:Insist___
链接:https://blog.csdn.net/Insist___/article/details/104372354