高并发编程基础

##高并发编程基础练习###############################################
练习1:
自定义容器,提供新增元素(add)和获取元素数量(size)方法。启动两个线程。
线程1向容器中新增10个数据。线程2监听容器元素数量,当容器元素数量为5时,线程2输出信息并终止。
使用volatile、CountDownLatch门栓、wait和notifyAll方法三种方式实现。
练习2:
(生产者消费者模式):
自定义同步容器,容器容量上限为10。可以在多线程中应用,并保证数据线程安全。

##高并发编程基础大纲###############################################
1.synchronized:
锁对象(this、临界对象、Class对象)、
同步方法、
同步代码块、
加锁目的、
同步方法和非同步方法调用、
同步方法和多方法调用、
同步方法调用其他方法、
同步方法继承、
同步方法锁异常、
同步粒度、
锁对象变更、
常量问题。
2.volatile关键字
3.AtomicXxx类
4.CountDownLatch门栓
5.wait()、notify()、notifyAll()
6.ReentrantLock:可重入锁、尝试锁、打断锁、公平锁

#####高并发编程基础详解################################################
一.synchronized关键字
1.synchronized锁对象包括:this(当前对象)、临界资源对象、Class类对象。
①锁对象this代码:【synchronized(this)和synchronized方法都是锁当前对象】
方式一:
private int count = 0;
public void testSync2(){
synchronized(this){
System.out.println(Thread.currentThread().getName()+“count=”+count++);
}
}
方式二:
private int count = 0;
public synchronized void testSync3(){
System.out.println(Thread.currentThread().getName()+“count=”+count++);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
②临界资源对象:
private Object o = new Object();
public void testSync1(){
synchronized(o){
System.out.println(Thread.currentThread().getName()+ “c:”+count++);
}
}
③Class类对象:【静态同步方法,锁的是当前类型的类对象。在本代码中就是Test_02.class】
方式一:
private static int staticCount = 0;
public static synchronized void testSync4(){
System.out.println(Thread.currentThread().getName() +“staticCount=”+staticCount++);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
方式二:
public static void testSync5(){
synchronized(Test_02.class){
System.out.println(Thread.currentThread().getName() +“staticCount=”+staticCount++);
}
}

2.同步方法、同步代码块
①同步方法:【重量锁一般不使用】
public synchronized void testSync3(){…}
public static synchronized void testSync3(){…}
②同步代码块:建议使用
private Object o = new Object();
public void testSync1(){
synchronized(o){
System.out.println(+ “count = " + count++);
}
}
public void testSync2(){
synchronized(this){
System.out.println(” count = " + count++);
}
}
3.synchronized加锁的目的:就是为了保证操作的原子性。
4.同步方法和非同步方法调用。
【同步方法只影响锁定同一个锁对象的同步方法。不影响其他线程调用非同步方法,或调用其他锁资源的同步方法】
5.同步方法多方法调用原子性问题。
同步方法只能保证当前方法的原子性问题。
多个方法要求结果访问原子性操作,需要多个方法都加锁,且锁定统一资源。
6.同步方法调用其他同步方法。
当锁对象是同一个时候,被称为可重入锁。
7.同步方法继承
子类同步方法覆盖父类同步方法。可以指定调用父类同步方法,相当于锁的重入。
重入锁相当于把两个线程和一起执行。
8.同步方法锁异常
当同步方法中出现异常的时候,会释放锁资源,不影响其他线程的执行。
9.同步粒度问题
在开发中尽力避免同步方法使用,使用同步代码块,细粒度解决同步问题,这样可以提供效率。
10.锁对象变更问题
同步代码一旦加锁后,就会有一个临时锁引用执行锁对象,和真实的引用无直接关系。
在锁位释放之前,修改锁对象引用,不会影响同步代码的执行。
11.常量问题
在定义同步代码时,不要使用常量来作为锁对象。

二.volatile关键字
1.volatile可见性:
通知os操作系统底层,在cup计算过程中,都要检查内存中数据的有效性。保证最新的内存数据被使用。
volatie只能保证可见性,不能保证原子性。

三.AtomicXxx
1.AtomicXxx:是同步类型(原子操作类型,其中的每一个方法都是原子操作,可以保证线程安全)。
实例如下:
public class Test_11 {
AtomicInteger count = new AtomicInteger(0);
void m(){
for(int i = 0; i < 10000; i++){
count.incrementAndGet(); //前++
}
}
public static void main(String[] args) {
final Test_11 t = new Test_11();
List threads = new ArrayList<>();
for(int i = 0; i < 10; i++){
threads.add(new Thread(new Runnable() {
public void run() {t.m();}
}));
}
for(Thread thread : threads){thread.start();}
for(Thread thread : threads){
try {
thread.join(); //把所线程连接一起执行
} catch (InterruptedException e) {e.printStackTrace();}
}
System.out.println(t.count.intValue());
}
}

三.CountDownLatch门栓
1.CountDownLatch门栓:
可以和锁混合使用,或者代替锁的功能。在门栓未完全开放之前等待,当门栓完全开放后执行。避免锁的效率低下问题。
2.实例代码:
public class Test_15 {
//在门上加5把锁
CountDownLatch latch = new CountDownLatch(5);
/等待门闩开发后执行/
void m1(){
try {
latch.await();// 等待门闩开放。
} catch (InterruptedException e) {e.printStackTrace();}
System.out.println(“m1() method”);
}
/*减门闩一直到0 */
void m2(){
for(int i = 0; i < 10; i++){
if(latch.getCount() != 0){
System.out.println("latch count : " + latch.getCount());
latch.countDown(); // 减门闩上的锁。
}
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {e.printStackTrace();}
}
}
/*main方法 */
public static void main(String[] args) {
final Test_15 t = new Test_15();
new Thread(new Runnable() {
public void run() {t.m1();}//等待门闩上的锁解开在执行
}).start();
new Thread(new Runnable() {
public void run() {t.m2();}//线程执行减门闩上的锁
}).start();
}
}

四.wait()、notify()、notifyAll()
wait: 线程进入等待队列。
notify: 只随机唤醒一个 wait 线程。
notifyAll: 唤醒其他等待所有线程。
1.实例代码:
class Test_02_Container{
List container = new ArrayList<>();
public void add(Object o){this.container.add(o);}
public int size(){return this.container.size();}
}
public class Test_02 {
public static void main(String[] args) {
final Test_02_Container t = new Test_02_Container();
final Object lock = new Object();
/这个线程负责取容器大小/
new Thread(new Runnable(){ public void run() {
synchronized (lock) {
if(t.size() != 5){
try {
lock.wait(); // 线程进入等待队列。
} catch (InterruptedException e) {e.printStackTrace();}
}
System.out.println(“size = 5”);
lock.notifyAll(); // 唤醒其他等待线程
}}}).start();
/这个线程负责取向容器放入内容/
new Thread(new Runnable() {public void run() {
synchronized (lock) {
for(int i = 0; i < 10; i++){
System.out.println("add Object to Container " + i);
t.add(new Object());
if(t.size() == 5){
lock.notifyAll();
try {
lock.wait();
} catch (InterruptedException e) {e.printStackTrace();}
}
}
}}}).start();
}
}

五.ReentrantLock
1.ReentrantLock重入锁:
Lock lock = new ReentrantLock(); //定义可重入锁
lock.lock(); // 加锁
lock.unlock(); // 解锁
2.实例代码:
public class Test_01 {
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(); // 解锁
}
}
void m2(){
lock.lock();
System.out.println(“m2() method”);
lock.unlock();
}
public static void main(String[] args) {
final Test_01 t = new Test_01();
new Thread(new Runnable() {public void run() {t.m1();}}).start();
new Thread(new Runnable() {public void run() {t.m2();}}).start();
}
}
3.尝试锁
①尝试锁说明:
Lock lock = new ReentrantLock();
isLocked = lock.tryLock(5, TimeUnit.SECONDS);
/*
* isLocked = lock.tryLock();
* 尝试锁, 如果锁,无法获取锁标记,返回false。如果获取锁标记,返回true.
* isLocked = lock.tryLock(5, TimeUnit.SECONDS);
* 阻塞尝试锁,阻塞参数代表的时长,尝试获取锁标记。【只锁释放才能获取尝试锁】
* 如果超时,不等待。直接返回。
* lock.unlock();
* 尝试锁在解除锁标记的时候,一定要判断是否获取到锁标记。
* 如果当前线程没获取到锁标记,会抛出异常。
*/

  ②代码实现:
  public class Test_02 {
Lock lock = new ReentrantLock();
void m1(){
 try{
   lock.lock();
   for(int i = 0; i < 4; i++){TimeUnit.SECONDS.sleep(1); System.out.println("m1() method " + i);}
 }
    catch(InterruptedException e){e.printStackTrace();}
finally{lock.unlock();}
}
void m2(){
  boolean isLocked = false;
  try{
    isLocked = lock.tryLock(1, TimeUnit.SECONDS); 
    if(isLocked){System.out.println("有锁");}
       else{System.out.println("无锁");}
  }
     catch(Exception e){e.printStackTrace();}
     finally{if(isLocked){lock.unlock();}}
}
public static void main(String[] args) {
  final Test_02 t = new Test_02();
  new Thread(new Runnable() {public void run() {t.m1();}}).start();
  new Thread(new Runnable() {public void run() {t.m2();}}).start();
}
 }

4.可打断锁【阻塞状态:包括普通阻塞\等待队列\锁池队列】
①可打断锁说明:
不可以打断:
wait()方法被调用,也是一种阻塞状态,只能由notify唤醒。无法打断
使用ReentrantLock的lock方法,获取锁标记的时候,如果需要阻塞等待锁标记,无法被打断。
可以打断:
使用ReentrantLock的lockInterruptibly方法,获取锁标记的时候,如果需要阻塞等待,可以被打断。
sleep(10000), 可以被打断。调用thread.interrupt()方法,可以打断阻塞状态,抛出异常。
②代码实现:
public class Test_03 {
Lock lock = new ReentrantLock();
void m1(){
try{
lock.lock();
for(int i = 0; i < 3; i++){
TimeUnit.SECONDS.sleep(1);
System.out.println(“m1()” + i);
}
}
catch(InterruptedException e){e.printStackTrace();}
finally{ lock.unlock(); }
}
void m2(){
try{
lock.lockInterruptibly();// 可尝试打断,阻塞等待锁。可以被其他的线程打断阻塞状态
System.out.println(“m2()”);
}catch(InterruptedException e){
System.out.println(“m2()interrupted”);
}finally{
try{
lock.unlock(); //这里出现异常需要if(lock.tryLock()){ lock.unlock(); }
}catch(Exception e){e.printStackTrace();}
}
}
public static void main(String[] args) {
final Test_03 t = new Test_03();
new Thread(new Runnable() {public void run() {t.m1();}}).start();
Thread t2 = new Thread(new Runnable() {public void run() {t.m2();}});
t2.start();
t2.interrupt(); //打断线程休眠。非正常结束阻塞状态的线程,都会抛出异常。
}
}

5.公平锁
①定义公平锁:
private static ReentrantLock lock = new ReentrantLock(true);

 ②公平锁代码实现:

public class Test_04 {
public static void main(String[] args) {
TestReentrantlock t = new TestReentrantlock();
//TestSync t = new TestSync();
Thread t1 = new Thread(t,“t1”);
Thread t2 = new Thread(t,“t2”);
t1.start();
t2.start();
}
}
class TestReentrantlock extends Thread{
private static ReentrantLock lock = new ReentrantLock();//定义一个公平锁
public void run(){
for(int i = 0; i < 5; i++){
lock.lock();
try{
System.out.println(Thread.currentThread().getName()+“getlock”);
}finally{lock.unlock();}
}
}
}
class TestSync extends Thread{
public void run(){
for(int i = 0; i < 5; i++){
synchronized (this) {
System.out.println(Thread.currentThread().getName() + “getlockinTestSync”);
}
}
}
}

发布了25 篇原创文章 · 获赞 0 · 访问量 1258

猜你喜欢

转载自blog.csdn.net/jinhuding/article/details/105004068