创建线程的方式
*继承Thread重写里面的run方法
*实现Runnable接口
*实现Callable接口
使用实现接口创建线程优势:线程类只是实现了接口,还可以再继承其他类;
使用实现接口创建线程劣势:如果要访问当前线程就需要使用Thread.currentThread()方法。
runnable和callable的区别:
1.callable有返回值,runnable没有返回值,callable可以看成是对runnable的补充。
2.callable规定重写的方法是call()方法,runnable规定重写的方法是run()方法。
3.call方法可以抛出异常,run方法不可以。

关于并行与并发
并行:多个处理器和多核处理器同时处理多个任务;可以看成多个咖啡机对应多个队列
并发:多个任务在同一个CPU核上,轮流分配时间片执行,所以看起来是在同时进行。可以看成一台咖啡机对应多个队列。

sleep()与wait()的区别
存在的类不同:sleep()方法来自Thread类,wait()方法来自Object类。
释放锁:sleep()不释放锁,wait()会释放锁。
使用方法的不同:sleep()可以设置时间,时间一到自动恢复或者调用interrupt()方法唤醒休眠中的线程;wait()可以使用notify()/notifyAll()直接唤醒

notify()和 notifyAll()的区别
notifyAll()方***唤醒所有的线程,notify()只唤醒一个线程。调用notifyAll()后,将等待的线程移到锁池之中参与竞争,竞争成功继续执行,如果不成功就继续留在池中等待锁释放再次参与竞争。而notify()具体唤醒哪个线程是由虚拟机控制的。

synchronized关键字
synchronized保证了它修饰的方法和代码块在任意时刻只能有一个线程执行,保证线程安全。
主要使用方式:修饰实例方法,修饰静态方法,修饰代码块;
对于普通同步方法:锁是当前实例化对象;
对于静态同步方法:锁是当前类的Class对象;
对于同步代码块,锁是synchronized括号里配置的对象;当一个线程试图访问同步代码块时,它首先必须要得到锁,退出和抛出异常时必须释放锁。