java高并发编程(三)
/**
* reentrantlock用于替代synchronized
* 本例中由于m1锁定this,只有m1执行完毕的时候,m2才能执行
* 这里是复习synchronized最原始的语义
* @author mashibing
*/
package yxxy.c_020; import java.util.concurrent.TimeUnit; public class ReentrantLock1 {
synchronized void m1() {
for(int i=0; i<10; i++) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
} } synchronized void m2() {
System.out.println("m2 ...");
} public static void main(String[] args) {
ReentrantLock1 rl = new ReentrantLock1();
new Thread(rl::m1).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(rl::m2).start();
}
}
二、使用ReentrantLock完成同样功能
/**
* reentrantlock用于替代synchronized
* 使用reentrantlock可以完成同样的功能
* 需要注意的是,必须要必须要必须要手动释放锁(重要的事情说三遍)
* 使用syn锁定的话如果遇到异常,jvm会自动释放锁,但是lock必须手动释放锁,因此经常在finally中进行锁的释放
* @author mashibing
*/
package yxxy.c_020; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class ReentrantLock2 {
Lock lock = new ReentrantLock(); void m1() {
try {
lock.lock(); //synchronized(this)
for (int i = 0; i < 10; i++) {
TimeUnit.SECONDS.sleep(1); System.out.println(i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} void m2() {
lock.lock();
System.out.println("m2 ...");
lock.unlock();
} public static void main(String[] args) {
ReentrantLock2 rl = new ReentrantLock2();
new Thread(rl::m1).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(rl::m2).start();
}
}
三、RenntrantLock的tryLock:
/**
* 使用reentrantlock可以进行“尝试锁定”tryLock,这样无法锁定,或者在指定时间内无法锁定,线程可以决定是否继续等待
* @author mashibing
*/
package yxxy.c_020; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class ReentrantLock3 {
Lock lock = new ReentrantLock(); void m1() {
try {
lock.lock();
for (int i = 0; i < 10; i++) {
TimeUnit.SECONDS.sleep(1); System.out.println(i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} /**
* 使用tryLock进行尝试锁定,不管锁定与否,方法都将继续执行
* 可以根据tryLock的返回值来判定是否锁定
* 也可以指定tryLock的时间,由于tryLock(time)抛出异常,所以要注意unclock的处理,必须放到finally中
*/
void m2() {
/*
boolean locked = lock.tryLock();
System.out.println("m2 ..." + locked);
if(locked) lock.unlock();
*/ boolean locked = false; try {
locked = lock.tryLock(5, TimeUnit.SECONDS);
System.out.println("m2 ..." + locked);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if(locked) lock.unlock();
} } public static void main(String[] args) {
ReentrantLock3 rl = new ReentrantLock3();
new Thread(rl::m1).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(rl::m2).start();
}
}
console:
0
1
2
3
4
5
m2 ...false
6
7
8
9
四、ReentrantLock的lockInterruptibly方法:
/**
* 使用ReentrantLock还可以调用lockInterruptibly方法,可以对线程interrupt方法做出响应,
* 在一个线程等待锁的过程中,可以被打断
*
* @author mashibing
*/
package yxxy.c_020; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function; public class ReentrantLock4 { public static void main(String[] args) {
Lock lock = new ReentrantLock(); Thread t1 = new Thread(()->{
try {
lock.lock();
System.out.println("t1 start");
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
System.out.println("t1 end");
} catch (InterruptedException e) {
System.out.println("interrupted!");
} finally {
lock.unlock();
}
});
t1.start(); Thread t2 = new Thread(()->{
try {
//lock.lock();
lock.lockInterruptibly(); //可以对interrupt()方法做出响应
System.out.println("t2 start");
} catch (InterruptedException e) {
System.out.println("interrupted!");
} finally {
lock.unlock();
}
});
t2.start(); try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.interrupt(); //打断线程2的等待 }
}
console:
t1 start
interrupted!
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
at yxxy.c_020.ReentrantLock4.lambda$1(ReentrantLock4.java:42)
at java.lang.Thread.run(Thread.java:745)
t1线程牢牢的拿到锁之后,一直sleep不会释放,如果t2线程中的run方法使用lock.lock(),那么t2线程就会一直傻傻的等着这把锁,不能被其他线程打断;
而使用lockInterruptibly()方法是可以被打断的,主线程main调用t2.interrupt()来打断t2,告诉他是不会拿到这把锁的,别等了;
报错是因为lock.unlock()这个方法报错的,因为都没有拿到锁,无法unlock();是代码的问题,应该判断有锁,已经锁定的情况下才lock.unlock();
五、ReentrantLock还可以指定为公平锁
默认的synchronized全都是不公平锁;
/**
* ReentrantLock还可以指定为公平锁
*
* @author mashibing
*/
package yxxy.c_020; import java.util.concurrent.locks.ReentrantLock; public class ReentrantLock5 extends Thread { private static ReentrantLock lock = new ReentrantLock(); //参数为true表示为公平锁,请对比输出结果 public void run() {
for(int i=0; i<100; i++) {
lock.lock();
try{
System.out.println(Thread.currentThread().getName()+"获得锁");
}finally{
lock.unlock();
}
}
}
public static void main(String[] args) {
ReentrantLock5 rl=new ReentrantLock5();
Thread th1=new Thread(rl);
Thread th2=new Thread(rl);
th1.start();
th2.start();
}
}
六、面试题:生产者消费者程序:
要求:写一个固定容量同步容器,拥有put和get方法,以及getCount方法,能够支持2个生产者线程以及10个消费者线程的阻塞调用
/**
* 面试题:写一个固定容量同步容器,拥有put和get方法,以及getCount方法,
* 能够支持2个生产者线程以及10个消费者线程的阻塞调用
*
* 使用wait和notify/notifyAll来实现
*
* @author mashibing
*/
package yxxy.c_021; import java.util.LinkedList;
import java.util.concurrent.TimeUnit; public class MyContainer1<T> {
final private LinkedList<T> lists = new LinkedList<>();
final private int MAX = 10; //最多10个元素
private int count = 0; public synchronized void put(T t) {
while(lists.size() == MAX) { //想想为什么用while而不是用if?
try {
this.wait(); //effective java
} catch (InterruptedException e) {
e.printStackTrace();
}
} lists.add(t);
++count;
this.notifyAll(); //通知消费者线程进行消费
} public synchronized T get() {
T t = null;
while(lists.size() == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
t = lists.removeFirst();
count --;
this.notifyAll(); //通知生产者进行生产
return t;
} public static void main(String[] args) {
MyContainer1<String> c = new MyContainer1<>();
//启动消费者线程
for(int i=0; i<10; i++) {
new Thread(()->{
for(int j=0; j<5; j++) System.out.println(c.get());
}, "c" + i).start();
} try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} //启动生产者线程
for(int i=0; i<2; i++) {
new Thread(()->{
for(int j=0; j<25; j++) c.put(Thread.currentThread().getName() + " " + j);
}, "p" + i).start();
}
}
}
1.为什么用while而不用if?
/**
* 面试题:写一个固定容量同步容器,拥有put和get方法,以及getCount方法,
* 能够支持2个生产者线程以及10个消费者线程的阻塞调用
*
* 使用Lock和Condition来实现
* 对比两种方式,Condition的方式可以更加精确的指定哪些线程被唤醒
*
* @author mashibing
*/
package yxxy.c_021; import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class MyContainer2<T> {
final private LinkedList<T> lists = new LinkedList<>();
final private int MAX = 10; //最多10个元素
private int count = 0; private Lock lock = new ReentrantLock();
private Condition producer = lock.newCondition();
private Condition consumer = lock.newCondition(); public void put(T t) {
try {
lock.lock();
while(lists.size() == MAX) {
producer.await();
} lists.add(t);
++count;
consumer.signalAll(); //通知消费者线程进行消费
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
} public T get() {
T t = null;
try {
lock.lock();
while(lists.size() == 0) {
consumer.await();
}
t = lists.removeFirst();
count --;
producer.signalAll(); //通知生产者进行生产
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return t;
} public static void main(String[] args) {
MyContainer2<String> c = new MyContainer2<>();
//启动消费者线程
for(int i=0; i<10; i++) {
new Thread(()->{
for(int j=0; j<5; j++){
System.out.println(c.get());
}
}, "c" + i).start();
} try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} //启动生产者线程
for(int i=0; i<2; i++) {
new Thread(()->{
for(int j=0; j<25; j++) {
c.put(Thread.currentThread().getName() + " " + j);
}
}, "p" + i).start();
}
}
}
八、ThreadLocal
/**
* ThreadLocal线程局部变量
*/
package yxxy.c_022; import java.util.concurrent.TimeUnit; public class ThreadLocal1 {
volatile static Person p = new Person(); public static void main(String[] args) { new Thread(()->{
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println(p.name);
}).start(); new Thread(()->{
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
p.name = "lisi";
}).start();
}
} class Person {
String name = "zhangsan";
}
/**
* ThreadLocal线程局部变量
*
* ThreadLocal是使用空间换时间,synchronized是使用时间换空间
* 比如在hibernate中session就存在与ThreadLocal中,避免synchronized的使用
*
* 运行下面的程序,理解ThreadLocal
*/
package yxxy.c_022; import java.util.concurrent.TimeUnit; public class ThreadLocal2 {
static ThreadLocal<Person> tl = new ThreadLocal<>(); public static void main(String[] args) { new Thread(()->{
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println(tl.get());
}).start(); new Thread(()->{
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
tl.set(new Person());
}).start();
} static class Person {
String name = "zhangsan";
}
}
console输出:null
java高并发编程(三)的更多相关文章
- [ 高并发]Java高并发编程系列第二篇--线程同步
高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...
- java高并发编程(一)
读马士兵java高并发编程,引用他的代码,做个记录. 一.分析下面程序输出: /** * 分析一下这个程序的输出 * @author mashibing */ package yxxy.c_005; ...
- 关于Java高并发编程你需要知道的“升段攻略”
关于Java高并发编程你需要知道的"升段攻略" 基础 Thread对象调用start()方法包含的步骤 通过jvm告诉操作系统创建Thread 操作系统开辟内存并使用Windows ...
- Java高并发编程基础三大利器之CountDownLatch
引言 上一篇文章我们介绍了AQS的信号量Semaphore<Java高并发编程基础三大利器之Semaphore>,接下来应该轮到CountDownLatch了. 什么是CountDownL ...
- java高并发编程(五)线程池
摘自马士兵java并发编程 一.认识Executor.ExecutorService.Callable.Executors /** * 认识Executor */ package yxxy.c_026 ...
- java高并发编程(四)高并发的一些容器
摘抄自马士兵java并发视频课程: 一.需求背景: 有N张火车票,每张票都有一个编号,同时有10个窗口对外售票, 请写一个模拟程序. 分析下面的程序可能会产生哪些问题?重复销售?超量销售? /** * ...
- java高并发编程(二)
马士兵java并发编程的代码,照抄过来,做个记录. 一.分析下面面试题 /** * 曾经的面试题:(淘宝?) * 实现一个容器,提供两个方法,add,size * 写两个线程,线程1添加10个元素到容 ...
- 《JAVA高并发编程详解》-并发编程有三个至关重要的特性:原子性,有序性,可见性
- [高并发]Java高并发编程系列开山篇--线程实现
Java是最早开始有并发的语言之一,再过去传统多任务的模式下,人们发现很难解决一些更为复杂的问题,这个时候我们就有了并发. 引用 多线程比多任务更加有挑战.多线程是在同一个程序内部并行执行,因此会对相 ...
随机推荐
- 洛谷 P3373:【模板】线段树 2(区间更新)
题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含三个整数N.M.P,分别 ...
- tomcat部署成https协议
1 生成密匙:进入jdk的bin目录后输入: keytool -genkeypair -alias "tomcat" -keyalg "RSA" -keysto ...
- 20165313 《Java程序设计》第九周学习总结
教材学习总结 1.URL类 :ava.net包中的URL类是对统一资源定位符的抽象,使用URL创建对象的应用程序称作客户端程序,客户端程序的URL对象调用InputStream openStream( ...
- 【liunx】Linux下的压缩和解压缩命令——jar
原文链接:http://blog.chinaunix.net/uid-692788-id-2681136.html JAR包是Java中所特有一种压缩文档,其实大家就可以把它理解为.zip包.当然也是 ...
- Writing and playing with custom Terraform Providers
转自:https://petersouter.xyz/writing-and-playing-with-custom-terraform-providers/ I’ve been digging de ...
- WikiBooks/Cg Programming
https://en.wikibooks.org/wiki/Cg_Programming Basics Minimal Shader(about shaders, materials, and gam ...
- 查看加密的vba代码
查看加密的vba代码,可以使用这个工具,excel文件里面的宏代码一览无余. https://files.cnblogs.com/files/laoxia/PVP.zip
- MySQL5.6新特性之Multi-Range Read
一 介绍 MySQL 5.6版本提供了很多性能优化的特性,其中之一就是 Multi-Range Read 多范围读(MRR) , 它的作用针对基于辅助/第二索引的查询,减少随机IO,并且将随机I ...
- 127.0.0.1 localhost 0.0.0.0 回环地址区别
127.0.0.1:一般认为是本机ip,这个没错.但是本机ip不只是 127.0.0.1 而是所有回环地址. 回环地址: 包括127.0.0.1在内的 所有 指向本机的地址.范围是 127.0.0. ...
- PCA原理解释
上图讲述的两组数据,可以看到左图的数据离散度比较大,相关性比较弱,右图数据的相关性比较强:我们在使用PCA的时候,就是要将相关性强的数据进行降维,以减少处理的数据量. 那么怎么描述数据的相关性呢? ...