1.卖票 (Lambda表达式)
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Liu Qingfeng
* @create 2021-02-10----21:20
*
* 多线程的实现。
*
* 将所有方法都压缩到资源类中,降低耦合
*
* 在接口中有且只有一个方法称为函数式接口,可以用Lambda Express
* 在这个接口上可以显示加上@FunctionalInterface 函数式接口。自己不写,系统会自动默认是@FunctionalInterface
*
* 因为只有一个方法所以可以省略方法名。
*
* 语法:
* () -> {};
*
*/
public class SaleTest {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(()->{ for (int i = 0; i < 30; i++) {ticket.saleTicket();} },"AA").start();
new Thread(()->{ for (int i = 0; i < 30; i++) {ticket.saleTicket();} },"BB").start();
new Thread(()->{ for (int i = 0; i < 30; i++) {ticket.saleTicket();} },"CC").start();
/* new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i<= 30; i++){
ticket.saleTicket();
}
}
},"AA").start(); //这里运行到start之后,不会立即执行,表示进入了就绪状态,等待操作系统CPU的空闲
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i<= 30; i++){
ticket.saleTicket();
}
}
},"BB").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i<= 30; i++){
ticket.saleTicket();
}
}
},"CC").start();*/
}
}
class Ticket{
private int ticket = 30;
private int i = 1;
private Lock lock= new ReentrantLock();
public void saleTicket() {
lock.lock();
try{
if (ticket > 0){
System.out.println(Thread.currentThread().getName() + "卖了第" + i++ + "张票了,还剩" + --ticket);
}
}finally {
lock.unlock();
}
}
}
2.线程通信
防止虚假唤醒
import com.sun.corba.se.impl.naming.cosnaming.NamingUtils;
import java.util.ArrayList;
import java.util.List;
/**
* @author Liu Qingfeng
* @create 2021-02-12----20:49
*
* 题目:现在两个线程,可以操作初始值为零的一个变量,
* 实现一个线程对该变量加1,一个线程对该变量-1,
* 实现交替,来10轮,变量初始值为0.
* 1.高内聚低耦合前提下,线程操作资源类
* 2.判断/干活/通知
*
* 题目2:现在4个线程,可以操作初始值为零的一个变量,
* 实现两个个线程对该变量加1,两个个线程对该变量-1,
* 实现加减交替,执行二十轮,变量初始值为0.
* 1.高内聚低耦合前提下,线程操作资源类
* 2.判断/干活/通知
* 3.防止虚假唤醒(判断只能用while,不能用if)
* 知识小总结:多线程编程套路+while判断
*/
public class SaleTest2 {
public static void main(String[] args) {
Number number = new Number();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
number.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
number.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
number.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
number.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
}
}
class Number{
private int num = 0;
public synchronized void increment() throws InterruptedException {
while (num != 0){
wait();
}
num++;
System.out.println(Thread.currentThread().getName() + "\t" + num);
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
while (num == 0) {
wait();
}
num--;
System.out.println(Thread.currentThread().getName() + "\t" + num);
this.notifyAll();
}
}
3.精确通知,顺序访问。Lock
new Reentrantlock().newCondition();
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Liu Qingfeng
* @create 2021-02-16----12:06
*
* Lock支持顺序唤醒
*
* A、B、C
*/
public class SaleTest2_2 {
public static void main(String[] args) {
Number2_2 number2_2 = new Number2_2();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
number2_2.countA();
}
},"A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
number2_2.countB();
}
},"B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
number2_2.countC();
}
},"C").start();
}
}
class Number2_2 {
private int flag = 1;
private Lock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
Condition conditionC = lock.newCondition();
public void countA() {
lock.lock();
try {
while (flag != 1){
conditionA.await();
}
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
flag = 2;
conditionB.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void countB() {
lock.lock();
try {
while (flag != 2){
conditionB.await();
}
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
flag = 3;
conditionC.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void countC() {
lock.lock();
try {
while (flag != 3) {
conditionC.await();
}
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
flag = 1;
conditionA.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
4.锁机制
不同的对象,不同的锁。
锁只锁同步方法(Synchronized)。不锁普通方法
静态同步方法,不管是几个对象调用的。都是一个锁
import sun.util.locale.provider.TimeZoneNameUtility;
import java.util.concurrent.TimeUnit;
/**
* @author Liu Qingfeng
* @create 2021-02-16----13:12
*/
public class SaleTest3 {
public static void main(String[] args) throws InterruptedException {
Phone phone = new Phone();
Phone phone1 = new Phone();
new Thread(() ->{
try {
phone.sendmail();
}catch (Exception e){
e.printStackTrace();
}
},"A").start();
Thread.sleep(100);
new Thread(() -> {
try {
phone1.hello();
}catch (Exception e){
e.printStackTrace();
}
},"B").start();
}
}
class Phone {
public static synchronized void sendmail(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("-----sendmail");
}
public static synchronized void hello(){
System.out.println("----hello");
}
}
5.集合不安全解决方法
ArrayList
* new Vector<>();
* Collections.synchronizedList(new ArrayList<String>());
* new CopyOnWriteArrayList(); //写时复制
Set
* Collections.synchronizedSet(new HashSet<String>());
* new CopyOnWriteArraySet(); //写时复制
Map
* Collections.synchronizedMap(new HashMap<String,Object>());
* new ConcurrentHashMap<String,Object>();
/**
* 1.故障现象
* 并发修改异常
* java.util.ConcurrentModificationException
* 2.导致原因
* 3.解决方法
* 3.1 new Vector<>();
* 3.2 Collections.synchronizedList(new ArrayList<String>());
* 3.3 new CopyOnWriteArrayList(); //写时复制
* 4.优化建议(同样的错误不犯第二次)
*
* 写时复制:
* CopyOnWrite容器即写时复制的容器。往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是现将当前容器Object[]进行Copy,
* 复制出一个新的容器Object[] newElements,然后新的容器Object[] newElements里添加元素,添加完元素之后,
* 再将原容器的引用指向新的容器setArray(newElements);。这样做的好处是可以对CopyOnWrite容器进行并发的读,
* 而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器
*/
public class NotSafeDemo3 {
public static void main(String[] args) {
mapNotSafe();
}
public static void mapNotSafe() {
Map<String,String> map = new ConcurrentHashMap<String, String>();
for (int i = 1; i <= 30; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,8));
System.out.println(map);
},String.valueOf(i)).start();
}
}
public static void setNotSafe() {
Set<String> set = new CopyOnWriteArraySet<String>();
for (int i = 1; i <= 30; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(set);
},String.valueOf(i)).start();
}
}
public static void listNotSafe() {
List<String> list = new CopyOnWriteArrayList();
for (int i = 1; i <= 30; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
6.Callable实现
用Callable接口要用他的实现类Future Task。
class MyThread2 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("******come in call method()");
return 1080;
}
}
/**
* 多线程中,第3种获得多线程的方式
*/
public class CallableDemo7 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask = new FutureTask(new MyThread2());
new Thread(futureTask,"A").start();
Integer result = futureTask.get();
System.out.println(result);
}
}
7.CountDownLatchDemo
import java.util.concurrent.CountDownLatch;
/**
* @author Liu Qingfeng
* @create 2021-02-17----11:17
*
* 保证主线程在计数完成之后,最后关闭线程。
*/
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t离开教室");
countDownLatch.countDown();
}).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "\t班长锁门走人");
}
}
8.CyclicBarrierDemo
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* @author Liu Qingfeng
* @create 2021-02-17----11:23
*/
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,() -> {
System.out.println("****召唤神龙");
});
for (int i = 1; i <= 7; i++) {
final int tempInt = i;
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t收集到" + tempInt + "星龙珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
9.SemaphoreDemo
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* @author Liu Qingfeng
* @create 2021-02-17----11:41
*
* 抢车位
* 用于资源的并发控制
*/
public class SemaphoreDemo {
public static void main(String[] args) {
/*
* 如果把资源改成1,那就是多线程抢一个资源。等同于Synchronized
*
* 如题:多线程抢一个资源,并对资源持有20s。
*
* */
Semaphore semaphore = new Semaphore(3); //模拟资源有三个空车位
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "\t抢到了车位");
TimeUnit.SECONDS.sleep(3); //停三秒离开
System.out.println(Thread.currentThread().getName() + "\t离开了车位");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
10.线程池
阻塞和不阻塞的区别
阻塞唤醒的时候会有上下文的切换
CPU时间片的切换
自旋锁就是通过cas算法自选,进行比较
自旋是为了避免阻塞唤醒,需要操作系统切换CPU状态,需要消耗一定时间。
为什么说线程上下文切换消耗资源
1.CPU系统的状态由用户态切换到内核态
2.保存上一个线程执行的指令指针写回到内存块,然后切换到一个新的线程,重新计算,并且在新的线程计算完了之后,还要把上次中断的线程,把他的中间变量再都会cpu,重新的回到中断的状态,再执行。。。
Collections.synchronizedSet(new HashSet<String>());
隐式锁synchronized
显式锁,上锁和解锁都要显式处理Reentrantlock
synchronized和实现了lock接口的都是悲观锁
ReentrantReadWriteLock.ReadLock算是一种乐观锁。
import java.util.concurrent.*;
/**
* @author Liu Qingfeng
* @create 2021-02-16----17:51
*/
public class ThreadPoolTest {
public static void main(String[] args) {
// //建五个线程
// ExecutorService threadPool = Executors.newFixedThreadPool(5);
//
// //建一个线程
// ExecutorService threadPool1 = Executors.newSingleThreadExecutor();
//
// //建可扩容个线程
// ExecutorService threadPool2 = Executors.newCachedThreadPool();
ExecutorService threadPool = new ThreadPoolExecutor(
2,
4,
2L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()
) ;
try {
//模拟十个用户办理业务
for (int i = 0; i < 10; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + "办理业务");
});
}
}catch (Exception exception){
exception.printStackTrace();
}finally {
threadPool.shutdown();
}
}
}
11.阻塞队列
四大函数式接口
12.volitial
13.Java锁
CAS