多线程(01)-基础

1.什么是线程、进程

一个进程可以有多个线程,如你打开qq是一个进程,但是聊天、开语音可能是一个一个的线程。
在这里插入图片描述

2 结构图

在这里插入图片描述
Thread类实现了Runnable接口。

3. 创建两种线程的方式?他们有什么区别?

继承Thread,实现了Runnable接口。
在这里插入图片描述
调用:
在这里插入图片描述
Runnabel是个接口,要通过实现类来进行调用。
start方法是启动一个线程,run方法是调用一个方法。

4. 线程的状态

在这里插入图片描述

5. 相关方法

sleep(),wait(), notify(),notifyAll(),yeild(),join()
sleep():线程阻塞不会释放锁,。
wait():线程阻塞会释放当前的锁,但是需要通过notify()来搭配使用,唤醒wait。
yeild():暂时让出cpu时间(一次,并不会一直让)。让其他线程去执行。
join():合并线程。
在这里插入图片描述

6.volatile、synchronized、lock

volatile:关键字是为了解决线程之间的可见性问题。
synchronized:既可以解决可见性也可以解决原子性问题。
什么是原子性:方法或代码块会执行完之后别的线程才可以来进行执行。
lock:可以完全替代synchronized,而且lock更加灵活。但是使用lock必须要手动释放锁unlock(),所以unlock常常会放在finally当中,以防发生异常。而且lock可以通过trylock()方法尝试获取锁。

7. 模拟死锁

死锁: 程序执行不下去了,一直处于等待或者锁住状态,释放不了。
如何避免: 注意方法调用的顺序
在这里插入图片描述在这里插入图片描述

7.1 如何避免死锁

  1. 有顺序的调用
  2. lock,超时检测
  3. JConsole工具检测

8 模拟消费者生产者

消费者+生产者+容器大小

  1. 可以使用wait、notifyAll来实现。
public class Thread_producer_consumer {

	static int num = 0;
	static int full = 10;
	static Object o = new Object();
	
	public static void main(String[] args) {
		
		// 生产者
		new Thread(new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				while (true) {
					try {
						Thread.sleep(1 * 1000);
					} catch (InterruptedException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					synchronized (o) {
						System.out.println("生产者开始生产了");
						if(num == full) {
							// 如果数量满了那么就进行等待消费
							try {
								o.wait();
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
						num++;
						System.out.println("++目前缓冲区里已经有:" + num);
						o.notify();
					}
				}
			}
		}).start();;
		
		// 消费者
		new Thread(new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				while (true) {
					try {
						Thread.sleep(3 * 1000);
					} catch (InterruptedException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					synchronized (o) {
						System.out.println("消费者开始消费了");
						if(num == 0) {
							// 如果缓冲区空了就等待
							try {
								o.wait();
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
						num--;
						System.out.println("--目前缓冲区里已经有:" + num);
						// notify并不会释放锁,只会唤醒了其他线程。
						o.notify();
						System.out.println("t_notify以后");
						/*
						 * for (int i = 0; i < 100; i++) { System.out.print(i); }
						 */
					}
				}
			}
			
		}).start();;
	}
}

  1. 可以使用lock,unlock来实现。
    在这里插入图片描述
    在这里插入图片描述
    区别: 使用lock效率更高,因为可以指定释放的是消费者或者生产者其中的一方。其中await()相当于wait(),signalAll()相当于notifyAll()。

9 countDownLatch的使用。

我靠,搞了我一个多小时时间。
用@Test注释方法,来进行测试不会管子线程是否还存活着,只有自己主线程执行完后就退出了jvm,程序自动关闭了。太坑了。


countDownLatch:允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。
countDownLatch里面有两个主要方法,await(),countDown(),getCount()。
await():阻塞线程,除非getCount()为0就释放,countDown()方法每次减一。

10 countDownLatch模拟高并发

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值