进程: 就是一个程序, 里面包含多个线程, 比如一个QQ程序
线程: 进程中最小的调度单元, 比如 QQ中的自动保存功能
并发: 多个线程操作同一资源, 抢夺一个cpu的执行片段, 快速交替
并行: 多个线程一起执行
线程有几个状态: NEW(新) , RUNNABLE(运行) , BLOCKED(阻塞) , WAITING(无限等待) , TIMED_WAITING(超时等待) , TERMINATED(死亡)
他们之前相互转换关系:
1、新建(new):线程对象被创建后就进入了新建状态。如:Thread thread = new Thread();
2、就绪状态(Runnable):也被称为“可执行状态”。线程对象被创建后,其他线程调用了该对象的start()方法,从而启动该线程。如:thread.start(); 处于就绪状态的线程随时可能被CPU调度执行。
3、运行状态(Running):线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权限,暂时停止运行。直到线程进入就绪状态,才有机会进入运行状态。阻塞的三种情况:
----4.1)等待阻塞:通过调用线程的wait()方法,让线程等待某工作的完成。
----4.2)同步阻塞:线程在获取synchronized同步锁失败(因为锁被其他线程占用),它会进入同步阻塞状态。
----4.3)其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或因异常退出了run()方法,该线程结束生命周期。
经典的卖票案例: 直接上代码
在这里 线程就是单独的 资源类, 属性--方法, 多个线程来操作同一资源, 这样写的好处是解耦
代码, synchronized 版本的经典的卖票案例
//这是一个资源类
class Ticket {
private int num = 300;
public synchronized void sale(){
if (num > 0) {
System.out.println(Thread.currentThread().getName()+"票的剩余个数为" + num--);
}
}
public static void main(String[] args) {
//多个线程操作同一资源, 这样写解耦,
Ticket ticket = new Ticket();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"线程-1").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"线程-2").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"线程-3").start();
}
}
代码, Lock 版本的经典的卖票案例:
public class LockDemo {
public static void main(String[] args) {
Ticket_L tick = new Ticket_L();
new Thread(()->{for (int i = 0; i < 40; i++) tick.sale();},"thread-1").start();
new Thread(()->{for (int i = 0; i < 40; i++) tick.sale();},"thread-2").start();
new Thread(()->{for (int i = 0; i < 40; i++) tick.sale();},"thread-3").start();
}
}
//这是一个资源类, 还是卖票案例
class Ticket_L {
private int num = 300;
private Lock lock = new ReentrantLock();
public void sale(){
//先加一把锁
lock.lock();
try {
if(num > 0){
System.out.println(Thread.currentThread().getName()+"票的剩余个数为" + num--);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
//释放锁
lock.unlock();
}
}
}
synchronized 和 Lock 区别:
1: synchronized 内置的java关键字, Lock是一个java类
2: synchronized 不能判断获取锁的状态, Lock 可以判断是否获取到了锁,有个方法: lock.tryLock(), 来判断是否已经加了锁
3: synchronized 自动释放锁, Lock必须手动释放锁, 不释放的话,容易造成死锁
4: synchronized 是阻塞的, 比如线程1(获取到锁, 阻塞), 线程2(就等待,一直等待), Lock锁,不一定会一直等下去
5、Synchronized 可重入锁,不可以中断的,非公平;Lock ,可重入锁,可以 判断锁,非公平(可以自己设置);
6、Synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码!