线程小结二
一、线程休眠
使用静态方法sleep(long millis)可以让当前进程暂停一段时间,进入休眠等待状态,实现人为的控制线程。
二、线程让步
通过yield()方法实现
yield()和sleep()的区别:yield()不会阻塞该线程,只是将线程转换成就绪状态,让线程的调度器重新调度一次。
三、线程插队
通过join()方法来完成
当在某个线程中调用其它线程的join()方法时,调用的线程将被阻塞,直到被join()加入的线程执行完成后才会继续执行
多线程同步
一、线程安全性
一个类是线程安全的,是指在被多个线程访问时,类是可以持续进行正确的行为。
线程安全问题就是由多个线程同时处理共享资源所导致的
二、同步代码块
当多个线程使用同一个共享资源时,可以将处理共享资源的代码放置到一个代码块中,使用sychronized关键字来修饰,被称作同步代码块
synchronized(lock){ 操作共享资源代码块 }
lock是一个锁对象,当线程执行同步代码块时,首先会检查锁对象的标志位,默认情况下为1,此时线程会执行同步代码块,并将锁对象的标志位置0。这时当一个新的线程执行到 这段同步代码块时,由于锁对象的标志位为0,新线程会发生阻塞,等待当前线程执行完同步代码块后,锁对象的标志位被置为1,新线程才能进入其中并执行。注意:同步代码块中的锁对象可以是任意类型的对象 ,但多个线程共享的锁对象必须是唯一的。“任意”说的是共享锁对象的类型。所以,锁对象的创建代码不能放到run()方法中,否则每个线程运行到run()方法都会创建一个新对象,这样每个线程都会有一个不同的锁,每个锁都有自己的标志位。
三、同步方法
在方法前加入synchronized修饰,被称为同步方法。此方法在某一时刻只允许一个线程访问,访问该方法的其他线程都会发生阻塞。
同步代码块的锁是自定义的任意类型的对象
同步方法的锁就是当前调用该方法的对象,就是this指向的对象。如果需要同步的方法是静态方法,这时会有疑问,静态方法不需要创建对象就可以直接用“类名.方法名()”方式来调用。如果不创建对象,静态同步方法的锁就不会是this,那么静态同步方法的锁是什么呢?java中静态方法的锁是该方法所在类的class对象,该对象可以直接用“类名.class” 的方式获取
同步代码块和同步方法解决多线程问题的优点:解决了多个线程同步时访问共享数据时的线程安全问题,只要加上同一个锁,在同一时间内只能有一条线程执行。
缺点:每次都会判断锁的状态,非常消耗资源,效率低下
四、死锁问题
两个线程都在等待对方的锁,便造成了程序的停滞,这种现象称为死锁。
多线程通信
解决这个多线程通信问题,需要控制多个线程按照一定的顺序轮流执行。Object类提供了wait()、notify()、notifyAll()方法用于解决线程间通信问题。
wait()使当前线程进入等待状态,notifu()和notifyAll()用于唤醒当前处于等待状态的线程。这三个方法的调用者都应该是同步锁对象,若不是JVM会抛出IllegalMonitorStateException异常