1、线程名称
以下代码输出Thread-0、Thread-1,因为虽然线程没开启,但在对象创建的时候就已经定义好名称了
package bear.utils; public class MainTest { public static void main(String[] args) { Deom d1 = new Deom(); Deom d2 = new Deom(); d1.run(); d2.run(); } } class Deom extends Thread{ @Override public void run() { System.out.println(getName()); } }
拿到当前运行线程对象,获取当前运行线程的名称,以下代码输出结果为:main
public class MainTest { public static void main(String[] args) { Deom d1 = new Deom(); d1.run(); // 改为d1.start();的话则输出Thread-0 } } class Deom extends Thread{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }
指定线程名称
public class MainTest { public static void main(String[] args) { Deom d1 = new Deom("hehe"); d1.start(); } } class Deom extends Thread{ Deom(String name){ super(name); } @Override public void run() { System.out.println(Thread.currentThread().getName()); } }
2、线程的生命周期
3、实现Runnable接口
好处
1,将线程的任务从线程的子类中分离出来,进行了单独的封装。按照面向对象的思想将任务的封装成对象。
2,避免了java单继承的局限性。
所以,这种方式创建线程较为常用。
原理
class Thread { private Runnable r; Thread() { } Thread(Runnable r) { this.r = r; } public void run() { if (r != null){ r.run(); } } public void start() { run(); } }
4、wait和sleep的区别
wait可以指定时间也可以不指定。sleep必须指定时间。
在同步中时,对cpu的执行权和锁的处理不同。
- wait:释放执行权,释放锁。
- sleep:释放执行权,不释放锁。
同步代码块中具备执行资格的可以有多个,但具备执行权的只能有一个
class Demo { void show() throws InterruptedException { synchronized (this) { // t0 t1 t2(此时t0 t1 t2都挂在这里了,当t3执行notifyAll的时候,这三者就都具备了执行权) wait(); // 当t3释放锁的时候,t0 t1 t2只能有一个线程能拿到锁,如t0拿到了锁,则在t0释放锁之前,t1和t2依然运行不了 } } void method() { synchronized (this) { notifyAll();// t3 } } }
5、停止线程
1,stop方法(已过时)
2,run方法结束(怎么控制线程的任务结束呢?任务中都会有循环结构,只要控制住循环就可以结束任务。控制循环通常就用定义标记来完成。)
但是如果线程处于了冻结状态,无法读取标记。如何结束呢?
可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备cpu的执行资格(中断睡眠状态)。
但是强制动作会发生InterruptedException,记得要处理。
public static void main(String[] args) throws InterruptedException { Thread t = new Thread() { private boolean flag = true; public void run() { while (flag) { try { System.out.println("hehe"); Thread.sleep(5000000); // wait() System.out.println("sleep over"); } catch (InterruptedException e) { flag = false; } } System.out.println("exit"); }; }; t.start(); Thread.sleep(200); // 执行中断之后,sleep over不会输出 t.interrupt(); }
当线程没有处于冻结状态时,也可以使用以下方法终止线程
public static void main(String[] args) throws InterruptedException { Thread t = new Thread() { public void run() { // 当主线程执行t.interrupt()的时候,interrupted()会返回ture while (!interrupted()) System.out.println("hehe"); // 再次调用interrupted()时,会返回false System.out.println(interrupted()); }; }; t.start(); Thread.sleep(200); t.interrupt(); }
6、守护线程
支持性线程,如垃圾回收线程,随程序的结束而结束。
如果虚拟机中剩下的所有线程都是守护线程的话,在所有线程会自动结束。
通过以下代码来指定线程为守护线程
setDaemon方法必须在start方法之前执行
如果setDaemon方法在start之后执行,那么会抛IllegalThreadStateException异常,同时线程依然为前台线程
/** * 守护线程方法演示 * * @author huangxj 2018年2月16日 * * @version v1.0 */ public class MainTest { public static void main(String[] args) { Thread t = new Thread(new Runnable() { @Override public void run() { while (true) { try { System.out.println("线程运行中。。。。"); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }); // t线程会随主线程的结束而结束 t.setDaemon(true); t.start(); } }
7、线程的join方法
在线程a中执行了线程b的join方法,那么线程a就会释放执行权和执行资格,让b线程先执行,等待b线程执行完毕后,a线程才会重新得到执行资格
/** * join方法演示 * * @author huangxj 2018年2月16日 * * @version v1.0 */ public class MainTest { public static void main(String[] args) throws InterruptedException { Thread t0 = new Thread(new Runnable() { @Override public void run() { for (int x = 0; x < 50; x++) { System.out.println(Thread.currentThread().getName() + "....." + x); } } }); t0.start(); System.out.println("主线程执行中,准备让t0线程先执行!"); // 执行了这一句之后,主线程会释放执行权和执行资格,等待t0线程执行完毕之后才重新获得执行资格 t0.join(); System.out.println("t0线程执行完毕!"); // 继续执行主线程的任务 for (int x = 0; x < 50; x++) { System.out.println(Thread.currentThread().getName() + "....." + x); } } }
8、线程的优先级
通过t0.setPriority来设置线程的优先级,优先级越高或cpu执行权的几率越高(1到10)
Thread t0 = new Thread(); t0.start(); t0.setPriority(Thread.MAX_PRIORITY);
9、线程组
创建线程时可以指定线程所属的线程组。
通过线程组可以对一堆线程执行批量操作。
public class MainTest { public static void main(String[] args) throws InterruptedException { Runnable run = new Runnable() { @Override public void run() { while(true) System.out.println(Thread.currentThread()); } }; ThreadGroup threadGroup0 = new ThreadGroup("threadGroup0"); Thread t0 = new Thread(threadGroup0, run); Thread t1 = new Thread(threadGroup0, run); t0.start(); t1.start(); Thread.sleep(1000); threadGroup0.stop(); } }
10、释放线程当前执行线程的执行权
通过调用Thread.yield()方法来实现
调用了该方法,当前线程会释放执行权,cpu将会执行其他线程
11、线程注意事项
以下代码输出:Thread run...
Runnable run = new Runnable() { @Override public void run() { System.out.println("Runnable run..."); } }; new Thread(run) { @Override public void run() { System.out.println("Thread run..."); } }.start();
以下代码有没有问题?如果有问题的话错误发生在哪一行?
发生在第一行,因为未实现抽象方法run(),要么类应该被abstract修饰
class Test implements Runnable{ public void run(Thread t){} }