一些概念
-
Monitor(监视器):
- 监视器是Java中的一种同步机制,用于协调多个线程对共享资源的访问。
- 每个Java对象都可以作为一个监视器,每个对象都有一个锁(也称为内部锁或监视器锁),用于控制对该对象的并发访问。
- 通过获取对象的锁,线程可以进入对象的临界区(或关键部分),只有一个线程可以在同一时刻执行临界区内的代码。
-
wait()方法:
wait()
是Object类的一个方法,用于将当前线程置于等待状态,直到另一个线程调用相同对象上的notify()
或notifyAll()
方法来唤醒它。- 当线程调用
wait()
方法时,它会释放对象的锁,允许其他线程进入临界区。 wait()
方法通常与条件变量一起使用,以等待某个条件的满足。
-
notify()方法:
notify()
也是Object类的一个方法,用于唤醒在相同对象上调用wait()
方法而进入等待状态的一个线程。- 注意,
notify()
只会唤醒一个等待的线程(具体哪个线程取决于线程调度器的选择),而其他等待的线程仍然会保持等待状态。
-
notifyAll()方法:
notifyAll()
也是Object类的一个方法,用于唤醒在相同对象上调用wait()
方法而进入等待状态的所有线程。- 相对于
notify()
,notifyAll()
更安全,因为它确保所有等待的线程都有机会被唤醒,从而避免了潜在的死锁问题。
创建线程
一般不用 Thread:
1)从解耦角度,run应该和类本身的创建分开,Thread是将run()进行重写,Runnable则调用传入对象的方法;
2)它用的是继承而非实现;
3)不能借助线程池
启动
使用start
start涉及两个线程:主线程和子线程。主线程执行start实际上是告诉jvm有空时创建子线程去执行。当上下文、栈、pc等资源准备后(就绪状态),等待cpu资源,之后才执行。
start不能重复调用,比如当第一个start执行后,线程进入end,此时就不能调用start重新启动了。源码来看,start一开始会判断线程状态是否为0,即未启动状态,然后把线程加入线程组,调用start0方法,并修改started状态。
start是让JVM创建线程去执行run,而直接调用run,则是由main来执行run
停止
使用interrupt通知而非强制。因为执行的线程本省更清楚如何来停止。
线程停止情况:正常执行完或者出现异常停止,其占据的资源会被JVM回收。
当线程在 sleep 等可响应中断的方法中被 interrupt,会抛异常。如果能保证 sleep 时收到 interrupt,就可以不使用 isInterrupted 判断。例如迭代中有 sleep,则不需要在迭代的条件中添加 isInterrupted。线程一旦响应中断就会把 isInterrupted 标记清除,所以如果在 while 里 try-catch sleep,是无法停止线程的。