多线程基础(新手入门必看)

本文介绍了多线程的基础知识,包括线程的概念、创建线程的两种方法、Thread类的常见方法、线程的属性、中断机制以及join()方法的使用。重点讲述了通过继承Thread类和实现Runnable接口创建线程,以及如何中断线程和等待线程结束。

一、线程概念
进程是系统分配资源的最小单位,线程是系统调度的最小单位。一个进程内的线程之间是可以共享资源的。每个进程至少有一个线程存在,即主线程。

二、创建线程的主要方法
1、方法一:继承Thread类
可以通过继承 Thread 来创建一个线程类,该方法的好处是 this 代表的就是当前线程,不需要通过 Thread.currentThread() 来获取当前线程的引用

public class ThreadTest3 {
    static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("我是一个新线程");
        }
    }

    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.start();
    }
}

2、方法二:实现Runnable 接口
通过实现 Runnable 接口,并且调用 Thread 的构造方法时将 Runnable 对象作为 target 参数传入来创建线程对象。 该方法的好处是可以规避类的单继承的限制;但需要通过 Thread.currentThread() 来获取当前线程的引用。

public class ThreadTest21 {
    static class MyRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "这里是线程运行的代码");
        }
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
    }
}

三、Thread 类及其常见的方法
1、Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。
2、常见的构造方法:

方法说明
Thread()创建线程对象
Thread(Runnable target)使用Runnable对象创建线程对象
Thread(String name)创建想成对象,并命名
Thread(Runnable target,String name)使用Runnable 对象创建线程对象,并命名

Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread(“这是我的名字”);
Thread t4 = new Thread(new MyRunnable(), “这是我的名字”);

四、Thread 几个常见的属性

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否有后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()

说明:
1、ID 是线程的唯一标识,不同线程不会重复。
2、名称是各种调试工具用到。
3、状态表示线程当前所处的一个情况。
4、优先级高的线程理论上来说更容易被调度到 。
5、关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
7、是否存活,即简单的理解,为 run 方法是否运行结束。

五、线程中断
目前常见的有以下两种方式:
1、 通过共享的标记来进行沟通

public class ThreadTest6 {
    private static boolean isQuit = false;
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread() {
            @Override
            public void run() {
                //此处是是用外部标记位来判定
                while (!isQuit) {
                    System.out.println("我在转账呢");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("转账被终止");
            }
        };
        thread.start();
        System.out.println("有内鬼终止交易");
        Thread.sleep(1000);
        isQuit = true;
    }
}

2.、调用 interrupt() 方法来通知

public class ThreadTest7 {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                //此处是用线程的内部标记位来判定
                //两种方法均可
                //while (!Thread.interrupted()){
                while (Thread.currentThread().isInterrupted()) {
                    System.out.println("我正在转账呢");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;
                    }
                }
                System.out.println("转账被终止");
            }
        };
        thread.start();
        System.out.println("有内鬼,终止交易");
        thread.interrupt();
    }
}

重点说明第二种方法:

  1. 通过 thread 对象调用 interrupt() 方法通知该线程停止运行
  2. thread 收到通知的方式有两种:
    (1) 如果线程调用了 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通知,清除 中断标志
    (2) 否则,只是内部的一个中断标志被设置,thread 可以通过
    1. Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志 。
    2. Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志。

第二种方式通知收到的更及时,即使线程正在 sleep 也可以马上收到。

六、等待一个线程—join()
有时,我们需要等待一个线程完成它的工作后,才能进行自己的下一步工作。例如,张三只有等李四转账成功,才决 定是否存钱,这时我们需要一个方法明确等待线程的结束。

public class ThreadTest11 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("我是线程1");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        Thread thread2 = new Thread() {
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("我是线程2");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread1.start();
        thread2.start();
        //thread1.join() 会先让thread1执行完毕才会执行下一个进程
        thread1.join();
        //thread2.join() 会先让thread2执行完毕才会执行下一个进程
        thread2.join();
        //由于前面两个都使用了join()这个方法,所以主线程要等钱两个线程执行完毕才继续执行主线程
        System.out.println("主线程执行完毕");
    }
}

附录

方法说明
public void join()等待线程结束
public void join(long millis)等待线程结束,最多等 millis 毫秒
public void join(long millis, int nanos)同理,但可以更高精度

七、获取当前线程的引用

方法说明
public static Thread currentThread();返回当前线程对象的引用
public class ThreadTest22 {     
	public static void main(String[] args) {        
 		Thread thread = Thread.currentThread(); 
        System.out.println(thread.getName());     
 	} 
 }

八、休眠当前线程
由于线程的调度是不可控的,所以,这个方法只能保证休眠时间是大于等于休眠时间的。

方法说明
public static void sleep(long millis) throws InterruptedException休眠当前线程 millis 毫秒
public static void sleep(long millis, int nanos) throws InterruptedException可以更高精度的休眠
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值