好久没有写博客,今天捞一捞多线程
废话不多说,开始搞!
第一种方式是通过类继承Thread,实现run方法
然后创建对象调用start方法,会自动执行run方法里面的代码
代码例子如下:
public class ThreadTest { public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); } static class MyThread extends Thread{ @Override public void run(){ for (int i = 0; i < 100; i++) { System.out.println("输出打印:"+i); } } } } 复制代码
第二种方式是通过实现Runnable接口
这种方式,需要我们创建两个对象, new Thread()
, 还有实现 Runnable的 类
调用start方法,同样会自动调用run方法里面的代码
代码例子如下:
public class RunnableTest { public static void main(String[] args) { Thread thread = new Thread(new MyRunnable()); thread.start(); } static class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("输出打印:"+i); } } } } 复制代码
第三种方式是实现Callable接口
这种比较厉害,能够获取线程执行完毕返回的结果.
使用的时候,我们需要创建一个 FutureTask
对象来包装我们我们实现类,
然后把这个对象传到Thread
的构造函数中,同样是调用start()方法
内部这次调用的是call
方法
public class CallableTest { public static void main(String[] args) { //FutureTask包装我们的任务,FutureTask可以用于获取执行直接 FutureTask<Integer> task = new FutureTask<>(new MyCallable()); Thread thread = new Thread(task); thread.start(); try { Integer result = task.get(); System.out.println(result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } static class MyCallable implements Callable<Integer>{ @Override public Integer call() throws Exception { int num = 0; for (int i = 0; i <= 100; i++) { num +=i; } return num; } } } 复制代码
用户线程执行完毕之后,守护线程就停止执行
设置代码:setDaemon()
下面我创建了两个线程(注意:我使用的是Lambad表达式)
第一个线程设置为守护线程,遍历0到100之间的数,每遍历一次睡眠200毫秒
第二线程默认为用户线程,遍历0到100之间的数,每遍历一次睡眠50毫秒
显然是第二个线程执行完毕先
通过执行代码可以发现第二个线程用户线程
执行完毕之后,第一个线程守护线程
就停止执行了
public class DaemonTest { public static void main(String[] args) { //守护线程 Thread t1 = new Thread(() -> { for (int i = 0; i < 100; i++) { try { Thread.sleep(200); System.out.println("t1:" + i); } catch (InterruptedException e) { e.printStackTrace(); } } }); t1.setDaemon(true); //设置守护线程 t1.start(); //用户线程 Thread t2 = new Thread(() -> { for (int i = 0; i < 100; i++) { try { Thread.sleep(50); System.out.println("t2:" + i); } catch (InterruptedException e) { e.printStackTrace(); } } }); t2.start(); } } 复制代码
线程的切换是由线程调度控制的,我们无法通过代码来进行干涉但是我们可以通过提高线程的
优先级
来最大程度的改善线程获取时间片的几率
一个CPU内核在同一个时间内,只能执行一个线程所以各个线程都在抢夺CPU时间,谁抢到了时间,就执行谁
例如:
A线程抢到了时间2秒,就执行2秒,然后挂起再去抢夺
B线程抢到了时间3秒,就执行3秒,然后挂起再去抢夺
线程的优先级被划分为10级,值分别为1-10
,10最高,线程中提供了3个常量表示最低,最高,以及默认的优先级
Thread.MIN_PRIORITY 1 // 最小等级 Thread.MAX-PRIORITY 10 // 最大等级 Thread.NORM_PRIOIRY 5 // 默认等级 void setPrioriy(int prioriy ) // 设置线程等级 复制代码
创建两个线程
第一个线程等级设置为 1
第二个线程等级设置为 10
通过执行代码,我们发现第二个线程抢到时间的概率是比第一个线程的概率高的
public class DaemonTest { public static void main(String[] args) { Thread t1 = new Thread(() -> { for (int i = 0; i < 10000; i++) { System.out.println("t1:"+i); } }); t1.setPriority(1);//设置优先级为 1,那么抢夺到资源的概率就小 t1.start(); Thread t2 = new Thread(() -> { for (int i = 0; i < 10000; i++) { System.out.println("t2:"+i); } }); t2.setPriority(10); //抢夺资源的概率高 t2.start(); } } 复制代码
注意:
如果没有设置等级的话,默认的线程等级为 5
有两个重要的方法
isInterrupted
,判断当前的线程是否已经中断了
interrupt
中断线程
注意:
stop()
中断线程的方法已经被Java抛弃了,它是通过抛异常的方式中断的,有比较大的误操作,导致事务回滚
示例代码创建一个线程
线程里面写了一个无限循环,每次循环,调用isInterrupted
方法,判断线程是否已经中断
如果已经中断了,可以去执行其他的代码逻辑
执行线程,睡眠2秒之后,调用interrupt
方法,中断线程
public class DaemonTest { public static void main(String[] args) { Thread t1 = new Thread(() -> { while (true){ boolean flag = Thread.currentThread().isInterrupted(); if (flag){ //如果线程中断了,你可以执行某些代码 }else{ System.out.println("线程执行中......."); } } }); t1.start(); try { //2秒之后中断线程 Thread.sleep(2000); t1.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } } 复制代码
线程的生命周期有NEW 新建对象状态
RUNNABLE 就绪,运行时状态
BLOCKED 加锁等待状态,待其他线程释放锁了执行
WAITING 调用wait等待状态 ,通过notify唤醒
TIMED_WAITING 睡眠状态,睡眠时间到了唤醒
TERMIANTED 销毁状态
在运行过程中,各个线程都在抢夺CPU的时间,没有抢夺到CPU时间在就绪
里面,随时准备执行
如果某个线程设置了加锁
,或者设置wait
,或者设置了sleep
,
线程就会进入阻塞状态,等待被唤醒,被唤醒之后,重新进入就绪
里面
`join()`可以理解为插队执行,例如我在A线程里面调用B线程的`join()`那么就会先执行B线程后再执行A线程
例如下面我创建了三个线程分别为t1,t2,t3
我的要求是他们的执行顺序必须要是先执行t1,再到t2,然后到t3
这时候就需要使用到了join
方法
当t2线程抢夺到了CPU时间,我调用t1线程的join方法插队执行
当t3线程抢夺到了CPU时间,我调用t2线程的join方法插队执行
public class DaemonTest { public static void main(String[] args) { Thread t1 = new Thread(() -> { for (int i = 0; i < 10; i++) { System.out.println("t1: "+ i); } }); Thread t2 = new Thread(() -> { try { t1.join(); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 10; i++) { System.out.println("t2: "+ i); } }); Thread t3 = new Thread(() -> { try { t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 10; i++) { System.out.println("t3: "+ i); } }); t1.start(); t2.start(); t3.start(); } } 复制代码
start() // 启动线程 getID() // 获取当前线程ID Thread-编号 (编号从0开启) getName() // 获取当前线程名称 stop() // 停止线程(不建议使用) getPriority() // 返回线程的优先级 isAlive() // 测试线程是否处于活动状态 isDaemon() // 测试线程是否为守护线程 isInterrupted() // 测试线程是否已经中断 Thread.currentThread() // 获取当前线程对象 复制代码