线程相关实例方法
获取线程ID- getId
- 在一个Java应用程序中,有一个long型的全局唯一的线程ID生成器threadSeqNumber,每new出来一个线程就会自增一次,从0开始,并且赋值给线程的tid属性。
- 用户只能获取ID,不能执行一个线程的ID,这是Thread类内部自己完成的。
获取和设置线程的名字
- 获取线程名 - 通过 - getName()方法获取线程对象名- 1 
 2
 3
 4
 5
 6- new Thread(){ 
 
 public void run() {
 System.out.println(this.getName());//Thread-0
 }
 }.start();
 
- 设置线程名 - 通过 - 构造函数传入String类型名- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13- new Thread("线程1"){ 
 
 public void run() {
 System.out.println(this.getName());//线程1
 }
 }.start();
 new Thread("线程2"){
 
 public void run() {
 System.out.println(this.getName());//线程2
 }
 }.start();- 1 
 2
 3
 4
 5- //Lambda表达式的Runnable方式,Thread的构造函数 
 Thread t2 = new Thread(() ->
 System.out.println("线程5的执行方法体"),"线程5");
 t2.start();
 System.out.println(t2.getName());//线程5
 
- 通过 - setName(String name)方法设置- 1 
 2
 3
 4
 5
 6
 7- new Thread(){ 
 
 public void run() {
 this.setName("线程3");
 System.out.println(this.getName());//线程3
 }
 }.start();- 1 
 2
 3
 4
 5
 6
 7
 8- Thread t1 = new Thread() { 
 
 public void run() {
 System.out.println(this.getName());//线程4
 }
 };
 t1.setName("线程4");
 t1.start();
1
2
3
4
5
6
7
8
Thread t1 = new Thread(()-> System.out.println("线程4的执行方法体"));
t1.setName("线程4");
t1.start();
System.out.println(t1.getName());//线程4
/*
        线程4
        线程4的执行方法体
  */
线程对象是否处于活动状态 - isAlive
- t.isAlive()测试线程t是否处于活动状态,只要- 线程启动并且没有终止,方法返回值就是- true。
- start()之前,线程不处于活动状态,之后就处于了活动状态。
获取当前线程的对象
- Thread.currentThread() 静态方法,获取当前执行线程, 主线程也可以获取- 1 
 2
 3
 4- //Runnable接口方式 
 //new Thread(Runnable target,String threadName) 构造方法
 new Thread(()-> System.out.println(Thread.currentThread().getName()),"线程6")
 .start();//线程6- 在main方法中可以获取主线程对象并设置: - 1 
 2- Thread.currentThread().setName("我是主线程"); 
 System.out.println(Thread.currentThread().getName());//我是主线程
休眠线程-sleep
- Thread.sleep(毫秒) / Thread.sleep(毫秒,纳秒)控制当前线程休眠若干毫秒- 1秒 = 1000毫秒
- 1秒 = 1000 1000 1000 纳秒 (100,000,000)
 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- new Thread(()->{ 
 for(int i = 0; i < 10 ;i++){
 System.out.println(Thread.currentThread().getName());
 try{
 Thread.sleep(1000); //每个线程休眠1秒(1000毫秒)
 }catch(InterruptedException e){
 e.printStackTrace();
 }
 }
 },"测试线程1").start();
- sleep方法不会释放锁,wait方法会释放锁
加入线程-join
- join()- 当前线程- 暂停,等待- 指定的线程执行结束后,- 当前线程才能再- 继续。即把指定的线程插队处理。
- join(int ms)可以等待指定的- 毫秒后再继续。
- join()方法会使调用该方法的线程处于运行状态,让一开始所在的线程处于无限阻塞状态,直到调用了join方法的线程执行完毕,线程销毁为止。
- 下面这个例子中,t2线程处于了阻塞状态,直到t1线程的run()方法执行完,线程死亡状态,t2线程才可以运行。
| 1 | public static void main(String[] args) { | 
执行结果:
| 1 | Thread-1bbb | 
结果显示:当t2线程执行两个后,t1使用join方法来插队,t1执行完之后,t2才继续执行完。
让出线程-yield
- Thread.yield()使- 该线程让出cpu,给其他线程使用cpu执行
- yield只会把时间片让给同优先级的线程
- 使CPU调度到其他线程,让该线程从运行状态回到可运行状态
设置线程优先级
- thread.setPriority(int priority)设置线程的优先级- Thread类源码中有三种优先级:(1,5,10) - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14- /** 
 * The minimum priority that a thread can have.
 */
 public final static int MIN_PRIORITY = 1;
 /**
 * The default priority that is assigned to a thread.
 */
 public final static int NORM_PRIORITY = 5;
 /**
 * The maximum priority that a thread can have.
 */
 public final static int MAX_PRIORITY = 10;
- 优先级值:默认为5,最大为10,最小为1; 
- 不能超过1~10这个范围。 
 - 1 
 2- t1.setPriority(Thread.MIN_PRIORITY);//最小 
 t1.setPriority(Thread.MAX_PRIORITY);//最大
中断线程-Interrupt
- 中断可以理解为线程的一个标志位,它表示了一个运行中的线程是否被其他线程进行了中断操作。
- 其他线程可以调用该线程的interrupt()方法对其进行中断操作,同时该线程可以调用isInterrupted()来感知其他线程对其是否进行了中断操作,从而做出相应。
- 也可以调用Thread中的静态方法interrupted()对当前线程进行中断操作,该方法会清除中断标志位。
- 当抛出InterruptedException时,会清除中断标志位,也就是说在调用isInterrupted会返回false。
- 如果线程调用了 wait()、sleep()、join()方法而导致的阻塞,可以中断线程,并抛出InterruptedException来唤醒
| 方法名 | 作用 | 备注 | 
|---|---|---|
| public void interrupt() | 中断该线程对象 | 如果线程调用了 wait()、sleep()、join()方法而导致的阻塞,可以中断线程,并抛出InterruptedException来唤醒,并且中断标志位会被清除 | 
| public boolean isInterrupted() | 测试该线程对象是否被中断 | 中断标志位不会被清除 | 
| public static boolean interrupted() | 测试当前线程是否被中断 | 中断标志位会被清除 | 
守护线程-Deamon
- setDaemon(boolean on)设置一个线程- 作为守护线程。
- 守护线程 - 为其他线程的运行- 提供便利的服务,最典型的应用便是GC线程 。
- 该线程 - 不会单独执行,当其他- 非守护线程都执行- 结束后,守护线程就没有可服务的对象了,就会- 自动退出。- 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18- public static void main(String[] args) { 
 Thread t1 = new Thread(()->{
 for (int i = 0; i < 3; i++) {
 System.out.println(Thread.currentThread().getName()+"非守护线程");
 }
 });
 Thread t2 = new Thread(()->{
 for (int i = 0; i < 30; i++) {
 System.out.println(Thread.currentThread().getName()+"守护线程");
 }
 });
 t2.setDaemon(true);//将t2设置成守护线程
 t1.start();
 t2.start();
 }- 第一次执行结果:
 - 1 
 2
 3- Thread-0非守护线程 
 Thread-0非守护线程
 Thread-0非守护线程- 说明:非守护线程直接执行完毕后, - 守护线程还未开启执行,就- 自动退出了。
- 第二次执行结果: - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- Thread-0非守护线程 
 Thread-1守护线程
 Thread-1守护线程
 Thread-0非守护线程
 Thread-0非守护线程
 Thread-1守护线程
 Thread-1守护线程
 Thread-1守护线程
 Thread-1守护线程
 Thread-1守护线程
- 根据结果发现,守护线程和非守护线程穿插执行,非守护线程执行完之后,守护线程继续执行了, - 没有立即停止,该现象为- 线程缓冲,即守护线程正在执行,需要等到非守护线程的- 执行完毕信号后,- 才能停止下来,自动退出。
 
wait()和notify()/notifyAll()
Object类中的wait()、notify()、notifyAll()三个方法,每个对象都是有的,结合多线程后可以起到很大的效果。
wait()
- wait()方法作用是使当前执行的代码的- 线程进行等待,当前线程会- 进入等待队列中。
- wait()代码处会- 停止执行,直到- 接到通知(notify())或者- 被中断(Interrupt())。
- 在调用wait()之前,线程必须获取该对象的锁,因此wait()方法只能在同步代码中调用执行。
- wait()方法可以使调用该线程的方法释放共享资源的锁,然后从运行状态退出,进入等待队列,直到再次被唤醒。
notify()
- 唤醒等待的线程,如果有- 多个线程在等待队列中,那么会- 随机挑选一个等待的线程,对其发出唤醒通知,并且- 使它等待获取该对象的对象锁。
- 等待获取对象锁说明了- 即使收到了通知,wait 的线程也不会马上获取对象锁,会在- 锁池中进行- 等待notify方法的线程释放锁才可以,- 获取了对象锁之后才能- 从锁池中出去进入- 可运行状态。
- 在调用notify()之前,和wait()一样,必须在同步代码中调用。因为有锁的操作。
- notify()不释放锁
notifyAll()
- notifyAll()方法可以使所有正在等待队列中等待同一共享资源的全部线程从等待状态退出,随机进入锁池,等待拿到对象锁,进入可运行状态。
如果wait()方法和notify()/notifyAll()方法不在同步方法/同步代码块中被调用,那么虚拟机会抛出java.lang.IllegalMonitorStateException
☆ sleep()和wait()的区别
- 方法本质上: - wait()方法时Object类中的实例方法。
- 而sleep()方法时Thread类中的静态方法
 
- wait()方法时
- 使用环境上: - wait()方法必须要在- 同步方法或同步代码块中使用,因为它必须已经获得对象锁。
- 而sleep()方法没有这个限制,它可以在任何地方使用。
 
- 是否释放锁: - wait()方法会- 释放占有的对象锁,使该线程- 进入等待池中。
- 而sleep()方法不会释放对象锁,只会让出CPU。
 
- 使其继续执行方式上: - wait()方法必须等待- notify()/notifyAll()方法的唤醒通知后,才会离开等待池并且如果- 再次获得CPU时间片才会继续执行。
- 而 - sleep()方法在- 休眠时间到达后,如果- 再次获得CPU时间片就会继续执行。
 
Java中用到的线程调度算法
- Java中用到的是抢占式的线程调度算法。一个线程用完CPU后,操作系统会根据线程优先级、线程饥饿程度等数据算出一个总的优先级并分配下一个时间片给某个线程。
Thread.sleep(0)的作用?
- 平衡CPU控制权的一种操作:- 由于Java采用的是抢占式线程调度算法,因此可能就会出现某条线程综合来看常常会获取到CPU的控制权的情况,为了让某些优先级较低的线程也能获得到CPU控制权,可以使用Thread.sleep(0)手动出发一次操作系统分配时间片的操作,来平衡控制权。
 
- 由于Java采用的是抢占式线程调度算法,因此可能就会