JAVA多线程

一 线程生命周期


二 创建线程的几种方式

public class T implements Runnable {

    public void m1() {
        System.out.println("m1 start");
    }

    public static void main(String[] args) {
        T t = new T();

        // 方式一:JDK1.8使用Lambda表达式
        new Thread(t::m1, "t1").start();
        new Thread(() -> {
            System.out.println("()-> start");
        }).start();

        // 方式二:实现Runnable接口
        new Thread(t).start();

        // 方式三:集成Thread类
        T2 t2 = new T2();
        t2.start();
    }

    @Override
    public void run() {
        System.out.println("run start");
    }

    // 继承Thread类
    public static class T2 extends Thread {
        @Override
        public void run() {
            System.out.println("T2 extends Thread{ start");
        }
    }
}

三 Synchronized 可重复锁

  • synchronized:是重量级锁,OS底层实现。Synchronized(Object)锁对象不能使用String、Integer等基本数据类型对象。
  • markword:偏向锁记录线程ID,当同一线程再次执行时,即可获得执行权限,发生线程争用时,升级为自旋锁。
  • 自旋锁:达到自旋10次以上时,再次锁升级,升级到synchronized重量级锁。
  • 锁只能升级,不能降级。
  • 自旋锁使用场景:加锁代码块执行时间少并且线程少。
  • 系统锁:加锁代码块执行时间长,线程数较多。

四 volatile

  • 保证变量在线程间的可见性
  • 禁止指令重排序

五 CAS 乐观锁(自旋)

cas 是 Compare And Swap 比较并替换的简称,其原理是cas(V 当前内存中的值,Expected 期望值,NewValue 变更后值)在并发量不大的情况下,可以代替Synchronized提供系统性能,cas的本质是自旋锁,当期望值 E 与 内存中值 V 相同时,NewValue 替换当前内存中值 V,当前内存值为 NewValue。如果期望值 E 与内存中值 V 不一致时,放弃当前操作。通过自旋原理,线程尝试更新。虽然CAS可以带来系统上性能的提升,但是也存在ABA问题。

六 ABA问题

ABA问题主要是CAS操作过程时,存在多个线程同时访问同一资源,线程A 首先将内存中的值变更为B,线程A又经过一系列操作,将内存中的值变更为A,线程B经过一段阻塞后,重新获得CPU执行,线程B发现内存值仍然是A,线程B将内存值又更新为B,由于多线程存在CPU资源占用,导致ABA问题的存在,为了解决ABA问题,我们引入版本号的概念避免了ABA问题的发生,通俗的一句话解释就是:你大爷还是你大爷,你大妈不再是你大妈了!!!

 

七 JDK中常见锁的应用

1、CyclicBarrier

CyclicBarrier 栅栏,当一组线程全部完成任务时,触发的线程。举例:由于疫情的影响,线下麻将馆全部关闭,大家纷纷通过手机的方式进行娱乐,这时,一个人事先开好了一个游戏房间,等待其它三位玩家进入,当所有玩家都进入房间后,游戏开始。游戏房间类似于CyclicBarrier,4玩家同比4个线程只有4个线程都完成后,游戏才能正式开始。

public class TestCyclicBarrier {

	public static void main(String[] args) {
		// 数量达到4,线程执行
		CyclicBarrier barrier = new CyclicBarrier(4, new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				System.out.println(Thread.currentThread().getName() + "房间人已满,开始对战");
			}
		});

		for (int i = 0; i < 20; i++) {
			new Thread(() -> {
				try {
					barrier.await();
					// System.out.println(Thread.currentThread().getName()+"已进入房间");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (BrokenBarrierException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}).start();
		}
	}
}

2、Phaser

phaser 阶段器,比 CyclicBarrier CountDownLanuc更加灵活,在我们现实生活中类似于一个班级的模拟考试,只有当学生全部到位时,才能开始第一门课程的考试,4门课程全部考试结束后,本次模拟考试正式结束。也可以理解成一个通过游戏,只有把每一关的怪兽全部消灭掉,才能进入下一关,直到完成通关。


public class TestPhaser {
	private static MyPash phaser = new MyPash();

	public static void main(String[] args) {
		phaser.bulkRegister(4);

		new Thread(new Person("ADC")).start();

		new Thread(new Person("盖伦")).start();

		new Thread(new Person("法师")).start();

		new Thread(new Person("皇子")).start();
	}

	static class Person implements Runnable {
		private String name;

		public Person(String name) {
			this.name = name;
		}

		public void arrived() {
			try {
				System.out.println(name + " 已进入游戏房间,即将开始第一关");
				phaser.arriveAndAwaitAdvance();
			} finally {
			}
		}

		public void second() {
			try {
				System.out.println(name + " 已进入游戏第二关,common on!!!");
				phaser.arriveAndAwaitAdvance();
			} finally {
			}
		}

		public void over() {
			try {
				if (name.equals("法师") || name.equals("ADC")) {
					System.out.println(name + "恭喜您通关");
					phaser.arriveAndAwaitAdvance();
				} else {
					System.out.println(name + ",已被 Npc Kill,等待其它玩家!!");
					phaser.arriveAndDeregister();
				}
			} finally {
			}
		}

		@Override
		public void run() {
			arrived();
			second();
			over();
		}

	}

	static class MyPash extends Phaser {
		@Override
		protected boolean onAdvance(int phase, int registeredParties) {
			switch (phase) {
			case 0:
				System.out.println("游戏开始,开始第一关!!!,剩余玩家 " + registeredParties);
				return false;
			case 1:
				System.out.println("第二关已通过,继续努力下一关!!!,剩余玩家" + registeredParties);
				return false;
			case 2:
				System.out.println("游戏结束,恭喜通关,剩余玩家" + registeredParties);
				return true;
			default:
				return true;
			}
		}
	}
}

3、Semaphore

业务场景限流,可以联想到现实生活中高速公路上的收费站,例如有一条单向8车道的高速公路,在某一处收费站只有三个收费窗口,当汽车想要通过收费站时,一种情况是大家抢着通过,谁先到达谁优先通过,还有一种是公平的方案,大家都排队出去。这里每一辆车可以理解为一个线程,收费窗口为某一资源。semaphore 在使用时可以设置是否公平的方式fair 为 true

public class TestSemaphore {

	public static void main(String[] args) {
		Semaphore semaphore = new Semaphore(1);
		new Thread(() -> {
			try {
				semaphore.acquire();
				System.out.println(Thread.currentThread().getName() + " 到达收费窗口,请扫码缴费");
				TimeUnit.SECONDS.sleep(2);
				System.out.println(Thread.currentThread().getName() + " 缴费完成");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				// TODO: handle finally clause
				semaphore.release();
			}
		}, "宝马X").start();

		new Thread(() -> {
			try {
				semaphore.acquire();
				System.out.println(Thread.currentThread().getName() + " 到达收费窗口,请扫码缴费");
				TimeUnit.SECONDS.sleep(2);
				System.out.println(Thread.currentThread().getName() + " 缴费完成");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				semaphore.release();
			}
		}, "奥迪A8").start();
	}
}

4、Exchanger

exchanger交换器,从语意上我们也能看出,交换只存在两者之间,不能有第三者,所有exchanger只有两个线程间的数据交换。

public class TestExchanger {

	static Exchanger<String> exchanger = new Exchanger<String>();

	public static void main(String[] args) {

		new Thread(() -> {
			String s = "我是A";
			try {
				s = exchanger.exchange(s);
				System.out.println(Thread.currentThread().getName() + "," + s);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}, "线程A").start();

		new Thread(() -> {
			String s = "我是B";
			try {
				s = exchanger.exchange(s);
				System.out.println(Thread.currentThread().getName() + "," + s);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}, "线程B").start();
	}
}

8、ReentrantLock

ReentrantLock 可循环锁

package com.test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestReentrantLock {

	Lock lock = new ReentrantLock();

	public void m1() {
		try {
			// 获得锁
			lock.lock();
			System.out.println(Thread.currentThread().getName() + "m1 获得锁……");
			m2();
			TimeUnit.SECONDS.sleep(5);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			// 释放锁
			System.out.println(Thread.currentThread().getName() + "m1 释放锁……");
			lock.unlock();
		}
	}

	public void m2() {
		try {
			// 获得锁
			System.out.println(Thread.currentThread().getName() + "m2 获得锁……");
			lock.lock();
		} finally {
			// 释放锁
			System.out.println(Thread.currentThread().getName() + "m2 释放锁……");
			lock.unlock();
		}
	}

	public static void main(String[] args) {
		TestReentrantLock reentrantLock = new TestReentrantLock();
		new Thread(reentrantLock::m1, "张三").start();

		new Thread(reentrantLock::m2, "李四").start();
	}
}

9、ReadWriteLock 读写锁(共享锁、排他锁)

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值