文章目录
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 如何避免死锁
- 有顺序的调用
- lock,超时检测
- JConsole工具检测
8 模拟消费者生产者
消费者+生产者+容器大小
- 可以使用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();;
}
}
- 可以使用lock,unlock来实现。
区别: 使用lock效率更高,因为可以指定释放的是消费者或者生产者其中的一方。其中await()相当于wait(),signalAll()相当于notifyAll()。
9 countDownLatch的使用。
我靠,搞了我一个多小时时间。
用@Test注释方法,来进行测试不会管子线程是否还存活着,只有自己主线程执行完后就退出了jvm,程序自动关闭了。太坑了。
countDownLatch:允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。
countDownLatch里面有两个主要方法,await(),countDown(),getCount()。
await():阻塞线程,除非getCount()为0就释放,countDown()方法每次减一。