U)7UUVCV}F]]FZ3QC@DI0BB.png

一、创建线程

  1. 继承Thread类,重写run方法

    1. // 继承Thread类创建线程
    2. public class Thread01 {
    3. public static void main(String[] args) {
    4. // 创建Cat对象当作线程使用
    5. Cat cat = new Cat();
    6. // public synchronized void start() {
    7. // start0();
    8. // }
    9. // private native void start0(); 本地方法,jvm调用。
    10. cat.start();// 启动线程 -> 会执行Cat的run方法
    11. // 不能是cat.run(); run方法是一个普通的方法,没有启动线程,会把run方法执行完再继续
    12. // main线程启动了一个子线程Thread-0,主线程不会阻塞,会继续执行
    13. // 主线程和子线程交替执行
    14. for(int i = 0;i<10;i++){
    15. System.out.println("主线程执行"+ Thread.currentThread().getName());
    16. }
    17. }
    18. }
    19. // 类继承了Thread类,该类就可以当作线程使用
    20. // run Thread类 实现了Runnable接口的run方法
    21. class Cat extends Thread{
    22. int times = 0;
    23. @Override
    24. public void run() {
    25. while (true){
    26. System.out.println("输出" + (++times) + "线程名=" +Thread.currentThread().getName());
    27. try {
    28. Thread.sleep(1000); // 每隔1秒
    29. } catch (InterruptedException e) {
    30. e.printStackTrace();
    31. }
    32. if(times == 80) {
    33. break; // 当times到80 退出循环,线程退出
    34. }
    35. }
    36. }
    37. }

    start()方法调用start0()方法后,该线程并不一定会立马执行,只是将线程变成可运行状态,什么时候执行取决于CPU

  2. 实现Runnable接口,重写run方法

java单继承,如果一个类已经继承了某个父类,这时不能再继承Thread类
实现Runnable接口方式更适合多个线程共享一个资源的情况,且避免了单继承的限制

  1. // 实现接口Runnable
  2. public class Thread02 {
  3. public static void main(String[] args) {
  4. Dog dog = new Dog(); // 不能调用start
  5. // 创建Thread对象,把dog对象放入Thread
  6. Thread thread = new Thread(dog);
  7. thread.start();
  8. }
  9. }
  10. class Dog implements Runnable{
  11. int count = 0;
  12. @Override
  13. public void run() {
  14. while (true) {
  15. System.out.println(++count + Thread.currentThread().getName());
  16. try {
  17. Thread.sleep(1000);
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }
  23. }
  • 多线程

    1. // 多线程 两个子线程
    2. public class Thread03 {
    3. public static void main(String[] args) {
    4. T1 t1 = new T1();
    5. T2 t2 = new T2();
    6. Thread thread1 = new Thread(t1);
    7. Thread thread2 = new Thread(t2);
    8. thread1.start();
    9. thread2.start();
    10. }
    11. }
    12. class T1 implements Runnable {
    13. private int count = 0;
    14. @Override
    15. public void run() {
    16. while (true){
    17. System.out.println("hello" + (++count));
    18. try {
    19. Thread.sleep(500);
    20. } catch (InterruptedException e) {
    21. e.printStackTrace();
    22. }
    23. }
    24. }
    25. }
    26. class T2 implements Runnable {
    27. private int count = 0;
    28. @Override
    29. public void run() {
    30. while (true) {
    31. System.out.println("hi" + (++count));
    32. try {
    33. Thread.sleep(500);
    34. } catch (InterruptedException e) {
    35. e.printStackTrace();
    36. }
    37. }
    38. }
    39. }

    二、线程终止

  1. 线程完成后,会自动退出
  2. 变量控制run方法退出的方式停止线程,即通知方式

    1. public class ThreadExit {
    2. public static void main(String[] args) throws InterruptedException {
    3. T t = new T();
    4. t.start();
    5. // 希望主线程控制t,终止,控制loop变量 -> 通知方式
    6. // 主线程休眠10秒(此时子线程还在运行),再通知t退出
    7. Thread.sleep(10000);
    8. t.setLoop(false);
    9. }
    10. }
    11. class T extends Thread {
    12. private boolean loop = true; // 控制变量
    13. private int count;
    14. @Override
    15. public void run() {
    16. while (loop) {
    17. try {
    18. Thread.sleep(50);
    19. } catch (InterruptedException e) {
    20. e.printStackTrace();
    21. }
    22. System.out.println("T 运行中" + (++count));
    23. }
    24. }
    25. public void setLoop(boolean loop) {
    26. this.loop = loop;
    27. }
    28. }

    三、线程常用方法

  3. setName 设置线程名称,使之与参数name相同

  4. getName 返回该线程的名称
  5. start 使该线程开始执行
  6. run 调用线程对象run方法
  7. setPriority 更改线程的优先级
  8. getPriority 获取线程的优先级
  9. sleep 在指定的毫秒数内让当前正在执行的线程休眠
  10. interrupt 中断线程,一般用于中断正在休眠的线程

    1. public class ThreadMethod01 {
    2. public static void main(String[] args) throws InterruptedException {
    3. Td t = new Td();
    4. t.setName("测试");
    5. t.setPriority(Thread.MIN_PRIORITY);
    6. t.start(); // 启动子线程
    7. // 主线程打印5个hi,就中断子线程休眠
    8. for (int i = 0; i < 5; i++) {
    9. Thread.sleep(1000);
    10. System.out.println("hi" + i);
    11. }
    12. System.out.println(t.getName()+ " 线程的优先级 = " + t.getPriority());
    13. t.interrupt(); // 中断t线程的休眠
    14. }
    15. }
    16. class Td extends Thread{
    17. @Override
    18. public void run() {
    19. for (int i = 0; i < 100; i++) {
    20. System.out.println(Thread.currentThread().getName() + " 输出");
    21. try {
    22. System.out.println(Thread.currentThread().getName() + " 休眠");
    23. Thread.sleep(200);
    24. } catch (InterruptedException e) {
    25. // 线程执行到一个interrupt方法时,会catch一个异常
    26. System.out.println(Thread.currentThread().getName() + " 被中断了");
    27. }
    28. }
    29. }
    30. }
  11. yield 礼让 不一定成功,礼让的时间不确定

  12. join 插队,一定成功,执行完插入的线程 ```java public class ThreadMethod02 { public static void main(String[] args) throws InterruptedException {

    1. T5 t5 = new T5();
    2. t5.start();
    3. for (int i = 1;i<=20;i++){
    4. Thread.sleep(1000);
    5. System.out.println("主线程"+i);
    6. if(i == 5) {
    7. System.out.println("让子线程先做");
    8. t5.join(); // 相当于让t5先执行 join 一定会成功
    9. // Thread.yield(); 礼让 不一定成功
    10. System.out.println("主线程继续");
    11. }
    12. }

    } }

class T5 extends Thread { @Override public void run() { for (int i = 1; i <= 20; i++) {

  1. try {
  2. Thread.sleep(1000);
  3. } catch (InterruptedException e) {
  4. e.printStackTrace();
  5. }
  6. System.out.println("子线程" + i);
  7. }
  8. }

}

  1. <a name="gigxV"></a>
  2. ## 四、用户线程和守护线程
  3. 1. 用户线程(工作线程),当线程的任务执行完或通知方式结束
  4. 1. 守护线程,一般是为工作线程服务,当所有的用户线程结束,守护线程自动结束 如 垃圾回收
  5. ```java
  6. public class ThreadMethod03 {
  7. public static void main(String[] args) throws InterruptedException {
  8. MyDaemonThread myDaemonThread = new MyDaemonThread();
  9. // 当main线程结束后,子线程自动结束 将子线程设为守护线程
  10. myDaemonThread.setDaemon(true);
  11. myDaemonThread.start();
  12. for (int i = 1; i<=10;i++){
  13. System.out.println("main 工作");
  14. Thread.sleep(1000);
  15. }
  16. }
  17. }
  18. class MyDaemonThread extends Thread {
  19. public void run(){
  20. for (;;) { // 无限循环
  21. try {
  22. Thread.sleep(1000);
  23. } catch (InterruptedException e){
  24. e.printStackTrace();
  25. }
  26. System.out.println("hhh");
  27. }
  28. }
  29. }

五、线程的生命周期

状态:

  1. NEW 尚未启动的线程状态
  2. RUNNABLE Java虚拟机中执行的线程状态 可以分为Ready和Running两个
  3. BLOCKED 阻塞
  4. WAITING 等待另一个线程执行特定动作的线程状态
  5. TIMEED_WAITING 等待另一个线程执行动作达到指定等待时间的线程状态
  6. TERMINATED 已退出

    1. public class ThreadState_ {
    2. public static void main(String[] args) throws InterruptedException {
    3. T6 t6 = new T6();
    4. System.out.println(t6.getName()+"状态" + t6.getState());
    5. t6.start();
    6. while (Thread.State.TERMINATED != t6.getState()){
    7. System.out.println(t6.getName() + " 状态" + t6.getState());
    8. Thread.sleep(500);
    9. }
    10. System.out.println(t6.getName()+ " 状态" + t6.getState() );
    11. }
    12. }
    13. class T6 extends Thread {
    14. @Override
    15. public void run() {
    16. while (true){
    17. for (int i = 0; i < 10; i++) {
    18. System.out.println("hi"+i);
    19. try {
    20. Thread.sleep(1000);
    21. } catch (InterruptedException e) {
    22. e.printStackTrace();
    23. }
    24. }
    25. }
    26. }
    27. }

    六、线程的同步 Synchronized

  7. 同步代码块

    1. synchronized (对象) {<br />}
  8. 同步方法

public synchronized void m(String name){
}

七、互斥锁

每个对象都对应于一个可称为互斥锁的标记,保证在任一时刻,只能有一个线程访问该对象
非静态的同步方法的锁可以是this,也可以是其他对象
静态的同步方法的锁为当前类本身

  1. public class SellTicket {
  2. public static void main(String[] args) {
  3. SellTicket03 sellTicket03 = new SellTicket03();
  4. new Thread(sellTicket03).start();
  5. new Thread(sellTicket03).start();
  6. new Thread(sellTicket03).start();
  7. }
  8. }
  9. //实现接口方式, 使用synchronized实现线程同步
  10. class SellTicket03 implements Runnable {
  11. private int ticketNum = 100;//让多个线程共享 ticketNum
  12. private boolean loop = true;//控制run方法变量
  13. Object object = new Object();
  14. //同步方法(静态的)的锁为当前类本身
  15. //1. public synchronized static void m1() {} 锁是加在 SellTicket03.class
  16. //2. 如果在静态方法中,实现一个同步代码块.
  17. /*
  18. synchronized (SellTicket03.class) {
  19. System.out.println("m2");
  20. }
  21. */
  22. public synchronized static void m1() {
  23. }
  24. public static void m2() {
  25. synchronized (SellTicket03.class) {
  26. System.out.println("m2");
  27. }
  28. }
  29. //1. public synchronized void sell() {} 就是一个同步方法
  30. //2. 这时锁在 this对象
  31. //3. 也可以在代码块上写 synchronize ,同步代码块, 互斥锁还是在this对象
  32. public /*synchronized*/ void sell() { //同步方法, 在同一时刻, 只能有一个线程来执行sell方法
  33. synchronized (/*this*/ object) {
  34. if (ticketNum <= 0) {
  35. System.out.println("售票结束...");
  36. loop = false;
  37. return;
  38. }
  39. //休眠50毫秒, 模拟
  40. try {
  41. Thread.sleep(500);
  42. } catch (InterruptedException e) {
  43. e.printStackTrace();
  44. }
  45. System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
  46. + " 剩余票数=" + (--ticketNum));
  47. }
  48. }
  49. @Override
  50. public void run() {
  51. while (loop) {
  52. sell();//sell方法是一共同步方法
  53. }
  54. }
  55. }

八、死锁

多个线程占用了对方的资源,但不相让

  1. public class DeadLock_ {
  2. public static void main(String[] args) {
  3. DeadLockDemo A = new DeadLockDemo(true);
  4. A.setName("A线程");
  5. DeadLockDemo B = new DeadLockDemo(false);
  6. B.setName("B线程");
  7. A.start();
  8. B.start();
  9. }
  10. }
  11. //线程
  12. class DeadLockDemo extends Thread {
  13. static Object o1 = new Object();// 保证多线程,共享一个对象,这里使用static
  14. static Object o2 = new Object();
  15. boolean flag;
  16. public DeadLockDemo(boolean flag) {
  17. this.flag = flag;
  18. }
  19. @Override
  20. public void run() {
  21. //1. 如果flag 为 T, 线程A 就会先得到/持有 o1 对象锁, 然后尝试去获取 o2 对象锁
  22. //2. 如果线程A 得不到 o2 对象锁,就会Blocked
  23. //3. 如果flag 为 F, 线程B 就会先得到/持有 o2 对象锁, 然后尝试去获取 o1 对象锁
  24. //4. 如果线程B 得不到 o1 对象锁,就会Blocked
  25. if (flag) {
  26. synchronized (o1) {//对象互斥锁
  27. System.out.println(Thread.currentThread().getName() + " 进入1");
  28. synchronized (o2) {
  29. System.out.println(Thread.currentThread().getName() + " 进入2");
  30. }
  31. }
  32. } else {
  33. synchronized (o2) {
  34. System.out.println(Thread.currentThread().getName() + " 进入3");
  35. synchronized (o1) {
  36. System.out.println(Thread.currentThread().getName() + " 进入4");
  37. }
  38. }
  39. }
  40. }
  41. }

九、释放锁

9.1 会释放锁的操作

  1. 当前线程的同步方法、同步代码块执行结束
  2. 当前线程在同步方法、同步代码块中遇到break、return
  3. 当前线程在同步方法、同步代码块中出现了未处理的Error或Exception,导致异常结束
  4. 当前线程在同步方法、同步代码块中执行了线程对象的wait()方法,当前线程暂停,并释放锁

    9.2 不会释放锁的操作

  5. 线程执行同步代码块或同步方法时,调用sleep()、yield()方法暂停当前线程的执行

  6. 线程执行同步代码块时,其它线程调用了该线程的suspend()方法将线程挂起