1.创建多线程
public classMultiThread {public static voidmain(String[] args) {//通过继承Thread类
Thread thread = newThread(){
@Overridepublic voidrun() {while(true){try{
Thread.sleep(500);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("1:" +Thread.currentThread().getName());
System.out.println("2:" + this.getName());
}
}
};
thread.start();//通过实现Runnable接口
Thread thread2 = new Thread(newRunnable(){
@Overridepublic voidrun() {while(true){try{
Thread.sleep(500);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("1:" +Thread.currentThread().getName());
}
}
});
thread2.start();//如果既继承runnable接口又实现了Thread类, 会执行哪个?
newThread(newRunnable(){public voidrun() {while(true){try{
Thread.sleep(500);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("runnable :" +Thread.currentThread().getName());
}
}
}
){public voidrun() {while(true){try{
Thread.sleep(500);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread :" +Thread.currentThread().getName());
}
}
}.start();
}
}
2.定时器Timer
定时任务就是靠多线程实现的
public classTimerTest {private static int count = 0;public static voidmain(String[] args) {class MyTimerTask extendsTimerTask{
@Overridepublic voidrun() {
count= (count+1)%2;
System.out.println("bombing!");new Timer().schedule(new MyTimerTask(),2000+2000*count);
}
}new Timer().schedule(new MyTimerTask(), 2000);while(true){
System.out.println(newDate().getSeconds());try{
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
3.互斥 synchronized
保证线程安全(数据完整性)
public classMultiThreadMutex {public static voidmain(String[] args) {newMultiThreadMutex().init();
}private voidinit(){final Outputer outputer = newOutputer();new Thread(newRunnable(){
@Overridepublic voidrun() {while(true){try{
Thread.sleep(10);
}catch(InterruptedException e) {
e.printStackTrace();
}
outputer.output("javaIsAPurelyObjectOrientedProgrammingLanguage");
}
}
}).start();new Thread(newRunnable(){
@Overridepublic voidrun() {while(true){try{
Thread.sleep(10);
}catch(InterruptedException e) {
e.printStackTrace();
}
outputer.output3("c++IsAMulti-paradigmSystems-levelProgrammingLanguage");
}
}
}).start();
}static classOutputer{public voidoutput(String name){int len =name.length();synchronized (Outputer.class)
{for(int i=0;i
System.out.print(name.charAt(i));
}
System.out.println();
}
}public synchronized voidoutput2(String name){int len =name.length();for(int i=0;i
System.out.print(name.charAt(i));
}
System.out.println();
}public static synchronized voidoutput3(String name){int len =name.length();for(int i=0;i
System.out.print(name.charAt(i));
}
System.out.println();
}
}
}
4.同步 wait/notify
保证线程间执行次序
//1. wait notify成对出现, 并且处于互斥锁的范围内//2. 要用while(condition)围住mutex.wait(), 因为存在虚假唤醒
public classMultiThreadSynchronization {public static voidmain(String[] args) {final Business business = newBusiness();newThread(newRunnable() {
@Overridepublic voidrun() {for(int i=1;i<=50;i++){
business.sub(i);
}
}
}
).start();for(int i=1;i<=50;i++){
business.main(i);
}
}
}classBusiness {private boolean bShouldSub = true;public synchronized void sub(inti) {while (!bShouldSub) {try{this.wait();
}catch(InterruptedException e) {
e.printStackTrace();
}
}for (int j = 1; j <= 10; j++) {
System.out.println("sub thread sequence of " + j + ",loop of " +i);
}
bShouldSub= false;this.notify();
}public synchronized void main(inti) {while(bShouldSub) {try{this.wait();
}catch(InterruptedException e) {
e.printStackTrace();
}
}for (int j = 1; j <= 100; j++) {
System.out.println("main thread sequence of " + j + ",loop of " +i);
}
bShouldSub= true;this.notify();
}
}
5.线程间传递参数
共享变量
/多个线程共享变量//以类中变量为中介; 以传入的共同参数为中介; 匿名内部类以主线程main中变量为中介;
public classMultiThreadShareData {public static voidmain(String[] args) {//传入共享参数 每个线程执行相同的代码
ShareData1 data1 = newShareData1();newThread(data1).start();newThread(data1).start();//传入共享参数
ShareData2 data2 = newShareData2();new Thread(newMyRunnable1(data2)).start();new Thread(newMyRunnable2(data2)).start();//匿名内部类实现变量的写法更简洁, 不需要传参
final ShareData2 data3 = newShareData2();new Thread(newRunnable(){
@Overridepublic voidrun() {
data3.decrement();
}
}).start();new Thread(newRunnable(){
@Overridepublic voidrun() {
data3.increment();
}
}).start();
}
}//方式1. 如果每个线程执行相同的代码 -> 多个Thread共享同一个runnable中的对象 少有可能
class ShareData1 implementsRunnable {private int count = 100;
@Overridepublic voidrun() {while (true) {synchronized(this) {
count--;
}
}
}
}//方式2.
classShareData2 {private int j = 0;public synchronized voidincrement() {
j++;
}public synchronized voiddecrement() {
j--;
}
}class MyRunnable1 implementsRunnable {privateShareData2 data1;publicMyRunnable1(ShareData2 data1) {this.data1 =data1;
}public voidrun() {
data1.decrement();
}
}class MyRunnable2 implementsRunnable {privateShareData2 data1;publicMyRunnable2(ShareData2 data1) {this.data1 =data1;
}public voidrun() {
data1.increment();
}
}
管道
public classMultiThreadPipe {public static voidmain(String[] args) {
PipedOutputStream pos= newPipedOutputStream();
PipedInputStream pis= newPipedInputStream();try{
pos.connect(pis);
}catch(IOException e) {
e.printStackTrace();
}newConsumer(pis).start();newProducer(pos).start();
}
}class Producer extendsThread {privatePipedOutputStream pos;publicProducer(PipedOutputStream pos) {this.pos =pos;
}public voidrun() {int i = 8;try{try{
Thread.sleep(2000);
}catch(InterruptedException e) {
e.printStackTrace();
}
pos.write(i);
}catch(IOException e) {
e.printStackTrace();
}
}
}class Consumer extendsThread {privatePipedInputStream pis;publicConsumer(PipedInputStream pis) {this.pis =pis;
}public voidrun() {try{
System.out.println(pis.read());
}catch(IOException e) {
e.printStackTrace();
}
}
}
6.ThreadLocal
该变量形式上共享, 但却是by线程独立
public classThreadLocalExample {private static ThreadLocal x = new ThreadLocal();public static voidmain(String[] args) {for (int i = 0; i < 2; i++) {new Thread(newRunnable() {
@Overridepublic voidrun() {int data = newRandom().nextInt();
System.out.println(Thread.currentThread().getName()+ " has put data :" +data);
x.set(data);
Person.getInstance().setName("name" +data);
Person.getInstance().setAge(data);newA().print();newB().print();
}
}).start();
}
}static classA{public voidprint(){int data =x.get();
System.out.println("A from " +Thread.currentThread().getName()+ " get data :" +data);
Person myData=Person.getInstance();
System.out.println("A from " +Thread.currentThread().getName()+ " getMyData: " + myData.getName() + "," +myData.getAge());
}
}static classB{public voidprint(){int data =x.get();
System.out.println("B from " +Thread.currentThread().getName()+ " get data :" +data);
Person myData=Person.getInstance();
System.out.println("B from " +Thread.currentThread().getName()+ " getMyData: " + myData.getName() + "," +myData.getAge());
}
}
}//javaBean的by线程的单例
classPerson {private static ThreadLocal personThreadLocal = new ThreadLocal();privatePerson(){}public static /*无需synchronized*/Person getInstance(){
Person instance=personThreadLocal.get();if(instance == null){
instance= newPerson();
personThreadLocal.set(instance);
}returninstance;
}privateString name;private intage;publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}public intgetAge() {returnage;
}public void setAge(intage) {this.age =age;
}
}
ThreadLocal实现原理
public classThreadLocalSimulation {private static Map threadData = new HashMap(); //核心
public static voidmain(String[] args) {for (int i = 0; i < 2; i++) {new Thread(newRunnable() {
@Overridepublic voidrun() {int data = newRandom().nextInt();
System.out.println(Thread.currentThread().getName()+ " has put data :" +data);
threadData.put(Thread.currentThread(), data);newA().get();newB().get();
}
}).start();
}
}static classA{public voidget(){int data =threadData.get(Thread.currentThread());
System.out.println("A from " +Thread.currentThread().getName()+ " get data :" +data);
}
}static classB{public voidget(){int data =threadData.get(Thread.currentThread());
System.out.println("B from " +Thread.currentThread().getName()+ " get data :" +data);
}
}
}
7. 线程池
池化技术都是防止频繁开关来提高系统性能, 代价是必须损耗一定空间来保存池
//池化技术之线程池
public classThreadPoolTest {public static voidmain(String[] args) {
ExecutorService threadPool= Executors.newFixedThreadPool(3); //限制线程数量//ExecutorService threadPool = Executors.newCachedThreadPool();//动态控制线程数量//ExecutorService threadPool = Executors.newSingleThreadExecutor();//跟一个线程类似, 但可以保证线程挂了有新线程接替
for(int i=1; i<=10; i++){final int task =i;
threadPool.execute(newRunnable(){
@Overridepublic voidrun() {for(int j = 1; j <= 10; j++){try{
Thread.sleep(20);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ " task:" + task + " loop:" +j);
}
}
});
}
System.out.println("all of 10 tasks have committed!");
threadPool.shutdown();//如果是shutdownNow方法会停止正在执行的任务//带定时器的线程池 schedule方法:xx时间以后执行; scheduleAtFiexedRate方法:xx时间后每隔yy时间执行
Executors.newScheduledThreadPool(3).scheduleAtFixedRate(newRunnable() {
@Overridepublic voidrun() {
System.out.println("bombing!");
}
},6, 2, TimeUnit.SECONDS);
}
}
8. Callable接口与Future
能实现返回线程执行结果 的效果
//返回结果的任务
public classCallableAndFuture {public static voidmain(String[] args) {//其一
ExecutorService threadPool =Executors.newSingleThreadExecutor();
Future future = threadPool.submit( //submit Callable而非execute Runnable
new Callable() {public String call() throwsException {//模拟handling
Thread.sleep(2000);return "hello";
};
});
System.out.println("等待结果");try{
System.out.println("拿到结果:" + future.get()); //阻塞等待结果,还有个get方法的重载版本,带超时参数, 超时抛异常. future/get的特点在于, 我们可以把任务合理分解, 在需要任务结果时调用get
} catch(InterruptedException e) {
e.printStackTrace();
}catch(Exception e) {
e.printStackTrace();
}
threadPool.shutdown();//不用该函数主线程是不会退出的//其二//ExecutorCompletionService包装线程池, take方法返回最先完成的Future任务
ExecutorService threadPool2 = Executors.newFixedThreadPool(10);
CompletionService completionService = new ExecutorCompletionService(threadPool2);for (int i = 1; i <= 10; i++) {final int seq =i;
completionService.submit(new Callable() {
@Overridepublic Integer call() throwsException {//模拟handling
Thread.sleep(new Random().nextInt(5000));returnseq;
}
});
}for (int i = 0; i < 10; i++) {try{
System.out.println(completionService.take().get());
}catch(InterruptedException e) {
e.printStackTrace();
}catch(ExecutionException e) {
e.printStackTrace();
}
}
threadPool2.shutdown();
}
}
9.Lock
ReentrantLock是具有synchronized功能的类
ReentrantReadWriteLock 粒度更细, 读与读不互斥, 写与写互斥, 读与写互斥
//使用Lock改写synchronized例子
public classLockTest {public static voidmain(String[] args) {newLockTest().init();
}private voidinit(){final Outputer outputer = newOutputer();new Thread(newRunnable(){
@Overridepublic voidrun() {while(true){try{
Thread.sleep(100);
}catch(InterruptedException e) {
e.printStackTrace();
}
outputer.output("javaIsAPurelyObjectOrientedProgrammingLanguage");
}
}
}).start();new Thread(newRunnable(){
@Overridepublic voidrun() {while(true){try{
Thread.sleep(100);
}catch(InterruptedException e) {
e.printStackTrace();
}
outputer.output("c++IsAMulti-paradigmSystems-levelProgrammingLanguage");
}
}
}).start();
}static classOutputer {
Lock lock= newReentrantLock();public voidoutput(String name) {int len =name.length();
lock.lock();try{for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}finally{
lock.unlock();
}
}
}
}
使用读写锁模拟缓存
//模拟缓存//加锁解锁要一致: 解没加过的锁会抛出异常; 加锁不解会造成死锁
public classCacheSimulation {public static voidmain(String[] args) {for (int i = 0; i < 10; ++i) {new Thread(newRunnable() {
@Overridepublic voidrun() {
String i= (String) getData("key");//out.println()参数为常量无并发问题; 为表达式时存在并发问题
System.out.println(i);
}
}).start();
}
}private static Map cache = new HashMap(); //保存缓存
private static ReadWriteLock rwl = newReentrantReadWriteLock();public staticObject getData(String key) {
rwl.readLock().lock();
Object value=cache.get(key);if (value == null) {
rwl.readLock().unlock();
rwl.writeLock().lock();if (cache.get(key) == null) { //防止几个线程都阻塞在writeLock.lock()
value = "abcde"; //模拟获取数据
System.out.println("get");
cache.put(key, value);
}
rwl.writeLock().unlock();
}returnvalue;
}
}
10.Condition
Condition具有wait/notify功能的类, 同样要配合Lock使用. 但与synchronized的waitnotify不同, 这里同一个Lock下可以创建多个Condition对象, 来实现粒度更细的控制
一个condition
//使用Condition改写线程同步示例, Condition由Lock.newCondition()而来//Condition.await/signal 对应 Mutex.wait/notify
public classConditionTest {public static voidmain(String[] args) {final Business business = newBusiness();new Thread(newRunnable() {
@Overridepublic voidrun() {for (int i = 1; i <= 50; i++) {
business.sub(i);
}
}
}).start();for (int i = 1; i <= 30; i++) {
business.main(i);
}
}static classBusiness {
Lock lock= newReentrantLock();
Condition condition=lock.newCondition();private boolean bShouldSub = true;public void sub(inti) {
lock.lock();try{while (!bShouldSub) {try{
condition.await();
}catch(Exception e) {
e.printStackTrace();
}
}for (int j = 1; j <= 10; j++) {
System.out.println("sub thread sequence of " + j + ",loop of " +i);
}
bShouldSub= false;
condition.signal();
}finally{
lock.unlock();
}
}public void main(inti) {
lock.lock();try{while(bShouldSub) {try{
condition.await();
}catch(Exception e) {
e.printStackTrace();
}
}for (int j = 1; j <= 20; j++) {
System.out.println("main thread sequence of " + j + ",loop of " +i);
}
bShouldSub= true;
condition.signal();
}finally{
lock.unlock();
}
}
}
}
两个condition, 下面模拟了数组阻塞队列
//有界缓冲区/数组阻塞队列 的模拟
classArrayBlockingQueueSimulation {final Lock lock = newReentrantLock();final Condition notFull =lock.newCondition();final Condition notEmpty =lock.newCondition();final Object[] items = new Object[100]; //长度
int putptr, takeptr, count; //初始为0
public void put(Object x) throwsInterruptedException {
lock.lock();try{while (count ==items.length) {
notFull.await();
}
items[putptr]=x;if (++putptr ==items.length) {
putptr= 0;
}++count;
notEmpty.signal();
}finally{
lock.unlock();
}
}public Object take() throwsInterruptedException {
lock.lock();try{while (count == 0) {
notEmpty.await();
}
Object x=items[takeptr];if (++takeptr ==items.length) {
takeptr= 0;
}--count;
notFull.signal();returnx;
}finally{
lock.unlock();
}
}
}
三个condition, 如下实现了三个线程轮流执行
public classThreeThreadsSynchronization {public static voidmain(String[] args) {final Business business = newBusiness();new Thread(newRunnable() {
@Overridepublic voidrun() {for (int i = 1; i <= 50; i++) {
business.sub2(i);
}
}
}).start();new Thread(newRunnable() {
@Overridepublic voidrun() {for (int i = 1; i <= 50; i++) {
business.sub3(i);
}
}
}).start();for (int i = 1; i <= 50; i++) {
business.main(i);
}
}static classBusiness {
Lock lock= newReentrantLock();
Condition condition1=lock.newCondition();
Condition condition2=lock.newCondition();
Condition condition3=lock.newCondition();private int shouldSub = 1;public void sub2(inti) {
lock.lock();try{while (shouldSub != 2) {try{
condition2.await();
}catch(Exception e) {
e.printStackTrace();
}
}for (int j = 1; j <= 20; j++) {
System.out.println("sub2 thread sequence of " + j + ",loop of " +i);
}
shouldSub= 3;
condition3.signal();
}finally{
lock.unlock();
}
}public void sub3(inti) {
lock.lock();try{while (shouldSub != 3) {try{
condition3.await();
}catch(Exception e) {
e.printStackTrace();
}
}for (int j = 1; j <= 10; j++) {
System.out.println("sub3 thread sequence of " + j + ",loop of " +i);
}
shouldSub= 1;
condition1.signal();
}finally{
lock.unlock();
}
}public void main(inti) {
lock.lock();try{while (shouldSub != 1) {try{
condition1.await();
}catch(Exception e) {
e.printStackTrace();
}
}for (int j = 1; j <= 30; j++) {
System.out.println("main thread sequence of " + j + ",loop of " +i);
}
shouldSub= 2;
condition2.signal();
}finally{
lock.unlock();
}
}
}
}
11. Semaphore
Semaphore信号量, 互斥锁保证多个线程同时访问同一个资源时的线程安全性, 信号量让线程动态匹配现有资源数, 来保证同时访问多个资源时的线程安全性, 并发更高.
Lock是哪个线程拿哪个线程负责释放; 信号量可以是一个线程获取, 另一个线程释放, 这个特性能用于死锁恢复.
public classSemaphoreTest {public static voidmain(String[] args) {
ExecutorService service=Executors.newCachedThreadPool();final Semaphore semaphore = new Semaphore(3);for (int i = 0; i < 10; i++) {
Runnable runnable= newRunnable() {public voidrun() {try{
semaphore.acquire();//线程进入时获取信号量
} catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() + "进入,当前已有" + (3 - semaphore.availablePermits()) + "个并发");try{
Thread.sleep((long) (Math.random() * 1000));
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() + "即将离开");
semaphore.release();//线程结束时释放信号量//下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
System.out.println("线程" + Thread.currentThread().getName() + "已离开,当前已有" + (3 - semaphore.availablePermits()) + "个并发");
}
};
service.execute(runnable);
}
service.shutdown();
}
}
12. CyclicBarrier
多个线程阶段点同步
public classCyclicBarrierTest {public static voidmain(String[] args) {
ExecutorService service=Executors.newCachedThreadPool();final CyclicBarrier cb = new CyclicBarrier(3);for (int i = 0; i < 3; i++) {
Runnable runnable= newRunnable() {public voidrun() {try{//模拟handling
Thread.sleep((long) (Math.random() * 1000));
System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点1,当前已有"
+ (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting() == 2 ? "都到齐了,继续走" : "正在等候"));
cb.await();//第一个同步点
Thread.sleep((long) (Math.random() * 1000));
System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点2,当前已有"
+ (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting() == 2 ? "都到齐了,继续走" : "正在等候"));
cb.await();//第二个同步点
Thread.sleep((long) (Math.random() * 1000));
System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点3,当前已有"
+ (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting() == 2 ? "都到齐了,继续走" : "正在等候"));
cb.await();//第三个同步点
} catch(Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
service.shutdown();
}
}
13.CountDownLatch
线程通过等待计数器归零来实现同步 实现一个人/多个人等待一个人/多个人的完成
public classCountdownLatchTest {public static voidmain(String[] args) {
ExecutorService service=Executors.newCachedThreadPool();final CountDownLatch cdOrder = new CountDownLatch(1); //初始计数器的数为1
final CountDownLatch cdAnswer = new CountDownLatch(3);for (int i = 0; i < 3; i++) {
Runnable runnable= newRunnable() {public voidrun() {try{
System.out.println("线程" + Thread.currentThread().getName() + "准备接受执行命令");
cdOrder.await();
System.out.println("线程" + Thread.currentThread().getName() + "已接到命令, 开始执行");//模拟handling
Thread.sleep((long) (Math.random() * 5000));
System.out.println("线程" + Thread.currentThread().getName() + "的分任务完成");
cdAnswer.countDown();
}catch(Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}try{
Thread.sleep((long) (Math.random() * 5000));
System.out.println("线程" + Thread.currentThread().getName() + "即将发送执行命令");
cdOrder.countDown();
System.out.println("线程" + Thread.currentThread().getName() + "已发送命令, 任务正在处理");
cdAnswer.await();
System.out.println("线程" + Thread.currentThread().getName() + "主管的所有任务完成");
}catch(Exception e) {
e.printStackTrace();
}
service.shutdown();
}
}
14. Exchanger
两个线程间互相交换数据
public classExchangerTest {public static voidmain(String[] args) {
ExecutorService service=Executors.newCachedThreadPool();final Exchanger exchanger = new Exchanger<>();
service.execute(newRunnable(){public voidrun() {try{
String data1= "王老吉";
System.out.println("线程" + Thread.currentThread().getName() + "正在把数据 " + data1 +" 换出去");
Thread.sleep((long)(Math.random()*2000));
String data2=(String)exchanger.exchange(data1);
System.out.println("线程" + Thread.currentThread().getName() + "换回的数据为 " +data2);
}catch(Exception e){
e.printStackTrace();
}
}
});
service.execute(newRunnable(){public voidrun() {try{
String data1= "加多宝";
System.out.println("线程" + Thread.currentThread().getName() + "正在把数据 " + data1 +" 换出去");
Thread.sleep((long)(Math.random()*2000));
String data2=(String)exchanger.exchange(data1);
System.out.println("线程" + Thread.currentThread().getName() + "换回的数据为 " +data2);
}catch(Exception e){
e.printStackTrace();
}
}
});
service.shutdown();
}
}
15. 阻塞队列
阻塞队列实现了BlockingQueue接口, 是生产者消费者模型的典范, 通过锁实现
put和take方法才具有阻塞功能
阻塞队列与线程同步 : 两个大小为1的空/满阻塞队列可以实现condition或wait/notify的效果
阻塞队列与Semaphore : 阻塞队列是一个线程存入数据, 一个线程取出数据; Semaphore一般用作同一线程获取和释放
public classBlockingQueueTest {public static voidmain(String[] args) {final BlockingQueue queue = new ArrayBlockingQueue<>(3);for (int i = 0; i < 2; i++) {newThread() {public voidrun() {while (true) {try{
Thread.sleep((long) (Math.random() * 1000));
System.out.println(Thread.currentThread().getName()+ "准备放数据!");
queue.put(1);
System.out.println(Thread.currentThread().getName()+ "已经放入数据, " + "队列目前有" + queue.size() + "个数据");
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}newThread() {public voidrun() {while (true) {try{
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+ "准备取数据!");
queue.take();
System.out.println(Thread.currentThread().getName()+ "已经取走数据, " + "队列目前有" + queue.size() + "个数据");
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
两个长度为1的空/满队列实现condition的效果
public classBlockingQueueImplSynchronization {public static voidmain(String[] args) {final Business business = newBusiness();new Thread(newRunnable() {
@Overridepublic voidrun() {for (int i = 1; i <= 20; i++) {
business.sub1(i);
}
}
}).start();for (int i = 1; i <= 20; i++) {
business.sub2(i);
}
}static classBusiness {
BlockingQueue queue1 = new ArrayBlockingQueue(1);
BlockingQueue queue2 = new ArrayBlockingQueue(1);
{try{
System.out.println("init");
queue2.put(1); //queue1为空 queue为满
} catch(InterruptedException e) {
e.printStackTrace();
}
}public void sub1(inti) {try{
queue1.put(1);
}catch(InterruptedException e) {
e.printStackTrace();
}for (int j = 1; j <= 10; j++) {
System.out.println("sub thread sequece of " + j + ", loop of " +i);
}try{
queue2.take();
}catch(InterruptedException e) {
e.printStackTrace();
}
}public void sub2(inti) {try{
queue2.put(1);
}catch(InterruptedException e1) {
e1.printStackTrace();
}for (int j = 1; j <= 20; j++) {
System.out.println("main thread sequece of " + j + ", loop of " +i);
}try{
queue1.take();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
16. 线程安全的非阻塞容器
并发集合
在JDK5之前, 多线程中对容器的操作部分需要手动加synchronized块保证线程安全
稍微轻便点的方式是使用Collections.synchronizedXXX()生成集合. 实现原理:通过装饰器模式在同名方法前添加synchronized(this), 来达到实现线程安全
但这是不完整的解决方案, 因为
1)装饰类的迭代器相关的代码没有加synchronized. 涉及到迭代还依然需要手动加synchronized块
2)迭代器遍历过程中除该迭代器外不能用其他方式增删元素(单线程在自身循环内, 多线程在不同线程执行不同部分), 否则抛出并发修改异常
3)最重要的, 并发低
//在集合的迭代器迭代过程中, 除了迭代器外不能对集合进行修改, 否则会抛出ConcurrentModificationException//ConcurrentModificationException的实现: 乐观锁, 记录一个版本号, 版本号不对抛异常
public classConcurrentModificationExceptionExample {public static voidmain(String[] args) {//Collection users = new CopyOnWriteArrayList();//若使用同步集合, 非迭代器修改就正常
Collection users = new ArrayList<>();
users.add(new User("张三", 28));
users.add(new User("李四", 25));
users.add(new User("王五", 31));
Iterator itrUsers=users.iterator();while(itrUsers.hasNext()) {
System.out.println("mark");
User user=(User) itrUsers.next();if ("张三".equals(user.getName())) {
users.remove(user);//非迭代器修改抛出异常//itrUsers.remove();//若使用迭代器修改, 则正常
} else{
System.out.println(user);
}
}
}
}
JDK5之后提出了很多线程安全的容器, 与前辈synchronized方式比起来, 它们的亮点并不是保证了线程安全, 而是它们在保证线程安全的同时尽量避免并发瓶颈
基本上限制条件多的容器都能实现Concurrent版本, 保持一定的读写并发; 像ArrayList LinkedList很难避开并发瓶颈, 退而求其次ArrayList实现了CopyOn保证了读并发;
LinkedList只能是通过Collections.synchronizedList()的synchronized方式(读|读都有锁), 尽量用其他集合替代.
ps:Collections.synchronizedList()或Vector的区别: 1.扩容量不同Vector 100%, SynchronizedList 50%. 2.Vector已对迭代器加锁, SynchronizedList需要手动加锁
原有集合
并发集合
原理
HashMap
ConcurrentHashMap
锁分段技术
HashSet
Collections.newSetFromMap(new ConcurrentHashMap())
用map版本实现
TreeMap
ConcurrentSkipListMap
用SkipList替代红黑树, CAS
TreeSet
ConcurrentSkipListSet
用map版本实现
Queue接口
ConcurrentLinkedQueue 非阻塞
CAS
ArrayList
CopyOnWriteArrayList
写时复制, 提高了读并发度; 以空间换取了部分写并发, 这点好坏需测试
Set接口
CopyOnWriteArraySet
用ArrayList版本实现, 用addIfAbsent()方法实现元素去重,写时还要复制, 因此写效率不佳
CAS原理类似乐观锁, 处理器保证底层实现, 理念:多次尝试肯定有一个能成(版本匹配则操作成功->该操作即具有原子性), 但会做很多无用功; 相比加锁能提高并发
17. 原子类
AtomicInteger等原子类用的是CAS, 并发比加锁高
实现多线程下安全性的要素: 原子性(不能被其他影响某变量的程序段打断) + 内存可见性 (一个线程修改, 另一个线程马上能看到)
synchronized: 实现了原子性和可见性
volatile: 实现内存可见性 CAS: 实现原子性