线程的实现
- 继承Thread类并重写run方法。 123456class MyThread extends Thread {public void run() {// 处理具体的逻辑}}
运行
- 通过定义实现Runnable接口的类进而实现 run方法123456class MyThread implements Runnable {public void run() {// 处理具体的逻辑}}
运行
人为停止线程推荐的方法
|
|
同步锁(synchronized)
成员变量与局部变量
1.如果一个变量是成员变量,那么多个线程对同一个对象是彼此影响的(一个线程对成员的改变会影响另一个线程)。
例子
运行结果
2.如果一个变量是局部变量,那么每个线程都有一个该局部变量的拷贝,一个线程对该局部变量的改变不会影响到其它的线程。
例子
运行结果
静态方法和非静态方法
Java 中的每个对象都有一个锁(lock)或者叫做监视器(monitor),当访问某个对象的 synchronized 方法时,表示将该对象上锁,此时其他任何线程都无法再去访问 该 synchronized 方法了,直到之前的那个线程执行方法完毕后(或者是抛出了异常)
, 那么将该对象的锁释放掉,其他线程才有可能再去访问该 synchronized 方法。
如果一个对象有多个 synchronized方法,某一时刻某个线程已经进入到了某个 synchronized方法 ,那么在该方法没有执行完毕前,其他线程是无法访问该对象的任何 synchronized方法 方法的。
运行结果
如果某个 synchronized 方法是 static 的,那么当线程访问该方法时,它锁的并不是 synchronized 方法所在的对象,而是 synchronized 方法所在的对象所对应的 Class 对 象,因为 Java 中无论一个类有多少个对象,这些对象会对应唯一一个 Class 对象。
运行结果
因此当线程分别访问同一个类的两个对象的两个 static,synchronized 方法时,他们 的执行顺序也是顺序的,也就是说一个线程先去执行方法,执行完毕后另一个线程 。
运行结果
同步代码块
表示线程在执行的时候会对 object 对象上锁,锁的只是方法的某一个代码块。
同步代码块是一种细粒度的并发控制,只会将块中的代码同步,位于方法内、同步代码块块之外的代码是可以被多个线程同时访问到的。
运行结果
wait及notify
wait的作用就是让使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。这时其它线程可抢夺控制权。
注意:一旦它重新获得对象的同步请求,所有之前的请求状态都 会恢复,也就是线程调用wait的地方的状态。线程将会在之前调用wait的地方继续运行下去。另一个会导致线程暂停的方法还有 Thread 类的 sleep 方法,它会导致线程睡眠指定 的毫秒数,但线程在睡眠的过程中是不会释放掉对象的锁的。
notify的作用就是唤醒请求队列中的一个线程,而notifyAll唤醒的是请求队列中的所有线程。
注意:被唤醒的线程不会马上运行,除非获取了该Object的锁。也就是说,调用notify的线程,在调用notify后,不会像wait一样,马上阻塞线程的运行。而是继续运行,直到相应的线程调度完成或者让出Object的锁。而被唤醒的线程会在当前线程让出Object锁后,与其他线程以常规的方式竞争对象锁。例子:
运行结果