商城网站建设那家好,关键词热度分析,网站推广招商,编程网页方法简介 方法名 功能 说明 start() 启动一个新线程#xff0c;在新的线程运行 run 方法中的代码 start 方法只是让线程进入就绪#xff0c;里面代码不一定立刻运行#xff08;CPU 的时间片还没分给它#xff09;。每个线程对象的start方法只能调用一次#xff0c;如… 方法简介 方法名 功能 说明 start() 启动一个新线程在新的线程运行 run 方法中的代码 start 方法只是让线程进入就绪里面代码不一定立刻运行CPU 的时间片还没分给它。每个线程对象的start方法只能调用一次如果调用了多次会出现IllegalThreadStateException run() 新线程启动后会调用的方法 如果在构造 Thread 对象时传递了 Runnable 参数则线程启动后会调用 Runnable 中的 run 方法否则默认不执行任何操作。但可以创建 Thread 的子类对象来覆盖默认行为 join() 等待线程运行结束 join(long n) 等待线程运行结束,最多等待 n 毫秒 getId() 获取线程长整型的 id id 唯一 getName() 获取线程名 setName(String) 修改线程名 getPriority() 获取线程优先级 setPriority(int) 修改线程优先级 java中规定线程优先级是1~10 的整数较大的优先级能提高该线程被 CPU 调度的机率 getState() 获取线程状态 Java 中线程状态是用 6 个 enum 表示分别为NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED isInterrupted() 判断是否被打断 不会清除 打断标记 isAlive() 线程是否存活还没有运行完毕 interrupt() 打断线程 如果被打断线程正在 sleepwaitjoin 会导致被打断的线程抛出 InterruptedException并清除 打断标记 如果打断的正在运行的线程则会设置 打断标记 park 的线程被打断也会设置 打断标记 interrupted() static判断当前线程是否被打断 会清除 打断标记 currentThread() static获取当前正在执行的线程 sleep(long n) static让当前执行的线程休眠n毫秒休眠时让出 cpu 的时间片给其它线程 yield() static提示线程调度器让出当前线程对CPU的使用 主要是为了测试和调试 start 和 run
结论
如果在主线程中 直接调用run方法这样其实并没有启动新线程还是在用main线程来执行并不能达到异步这样的效果。
使用 start 是启动新的线程通过新的线程间接执行 run 中的代码。
因此启动一个线程必须用 start方法再用新的线程去调用run方法。
示例直接调用 run
public static void main(String[] args) {Thread t1 new Thread(t1) {Overridepublic void run() {log.debug(Thread.currentThread().getName());FileReader.read(Constants.MP4_FULL_PATH);}};t1.run();log.debug(do other things ...);
}
输出结果 19:39:14 [main] c.TestStart - main 19:39:14 [main] c.FileReader - read [1.mp4] start ... 19:39:18 [main] c.FileReader - read [1.mp4] end ... cost: 4227 ms 19:39:18 [main] c.TestStart - do other things ... 可以看到没有产生新线程都是主线程方法调用还是同步的必须等 FileReader.read()方法执行完才能往下做“do other things ...”
调用 start
将上面的 t1.run() 改成 t1.start()
输出 19:41:30 [main] c.TestStart - do other things ... 19:41:30 [t1] c.TestStart - t1 19:41:30 [t1] c.FileReader - read [1.mp4] start ... 19:41:35 [t1] c.FileReader - read [1.mp4] end ... cost: 4542 ms 可以看到产生了新线程t1方法的调用是异步的不用等FileReader.read()方法执行完也能往下做“do other things ...”
sleep 与 yield
sleep
静态方法
Thread.Sleep(1000);
//静态方法让当前正在执行的线程进入休眠暂时停止执行指定的毫秒数。
作用
调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态阻塞
注意
在哪个线程里就让那个线程睡眠main方法中的thread.sleep()并不是使我们的子线程进入休眠而是使我们的主线程进入休眠因为sleep()方法是使当前线程进入休眠
睡眠结束后的线程未必会立刻得到执行
建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性下面代码都是睡眠1秒但是TimeUnit可读性更高里面可以选时间的单位而sleep就是用毫秒。
public static void main(String[] args) {Thread.sleep(1000);TimeUnit.SECONDS.sleep(1);
}
打断睡眠
其它线程可以使用 interrupt 方法打断正在睡眠的线程将其叫醒这时 sleep 方法会抛出 InterruptedException yield
英文意思是让出、让步
调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态然后调度执行其它线程
具体的实现依赖于操作系统的任务调度器如果没有其他线程CPU空闲时那么任务调度器会让其执行也就是你别谦让了没有其他人了你来吧。
异同
都是让线程先不占用cpu
sleep是进入到 阻塞状态yield是进入到 就绪状态就绪状态的线程是可以被任务调度器调用执行的但是阻塞状态的不可以。
sleep有时间参数用于睡眠多少毫秒。yield没有时间参数
sleep应用提高CPU效率
在没有利用cpu来计算时不要让while(true)空转浪费cpu这时可以使用yield或sleep来让出 cpu的使用权给其他程序
例如下面的代码通常有些服务器端会有while (true)这样的循环来一直执行接收请求并响应但是如果一直while (true)那么CPU会一直执行它导致大部分时间都是空转所以加一个睡眠不用睡眠太久就可以让CPU的执行效率提高很多。
while (true){try {Thread.sleep(50);}catch (InterruptedException e){e.printStackTrace();}
}
join
作用
t1.join();
等待t1线程运行结束
为什么需要 join
下面的代码执行打印 r 是什么
static int r 0;
public static void main(String[] args) throws InterruptedException {test1();
}
private static void test1() throws InterruptedException {log.debug(开始);//t1 线程修改 静态变量r的值Thread t1 new Thread(() - {log.debug(开始);sleep(1);log.debug(结束);r 10;});//t1 线程启动t1.start();//主线程进行打印log.debug(结果为:{}, r);log.debug(结束);
}分析
因为主线程和线程 t1 是并行执行的t1 线程需要 1 秒之后才能算出 r10
而主线程一开始就要打印 r 的结果所以只能打印出 r0
解决方法
如何让主线程打印出最新的也就是经过t1线程修改完毕后的r的值呢
让主线程也进行睡眠让主线程睡眠的时间久一点这样显然不好因为不好控制睡眠时间而且t1线程睡眠完毕后不一定会被任务调度器马上调用所以情况很复杂。
这时候就可以用 join解决这个问题只需要在 t1.start(); 后面加上一个 t1.join(); 即可这样主线程会等待t1线程执行完毕再执行。
有时效的 join
t1.join(1500);
interrupt
作用
可以打断正在运行的线程也可以打断正在阻塞的线程。
如果打断正在阻塞中的线程那么会让线程进入阻塞状态如果打断正在运行的线程那么就会打断之但实际上不是强行打断而是告诉其他线程我要打断你由其他线程决定自己是否要结束。
打断正在阻塞中的线程
打断 sleepwaitjoin 的线程
这几个方法都会让线程进入阻塞状态
打断 sleep 的线程, 会清空打断状态也就是打断状态变成false
以 sleep 为例
private static void test1() throws InterruptedException {Thread t1 new Thread(()-{sleep(1);}, t1);t1.start();sleep(0.5);//主线程先小等一会让t1线程进入睡眠t1.interrupt();//主线程打断t1线程log.debug( 打断状态: {}, t1.isInterrupted());//输出打断标记
}
输出 java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at java.lang.Thread.sleep(Thread.java:340) at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386) at cn.itcast.n2.util.Sleeper.sleep(Sleeper.java:8) at cn.itcast.n4.TestInterrupt.lambda$test1$3(TestInterrupt.java:59) at java.lang.Thread.run(Thread.java:745) 21:18:10.374 [main] c.TestInterrupt - 打断状态: false 打断正常运行的线程
打断正常运行的线程, 不会清空打断状态也就是打断状态会变成true private static void test2() throws InterruptedException {Thread t2 new Thread(()-{while(true) {Thread current Thread.currentThread();boolean interrupted current.isInterrupted();if(interrupted) {log.debug( 打断状态: {}, interrupted);break;}}}, t2);t2.start();sleep(0.5);t2.interrupt();
}输出 20:57:37.964 [t2] c.TestInterrupt - 打断状态: true 如果只写一个 while true 里面没有判断的话那么这个主线程是打断不了t2线程的。
因为interrupt实际上不能打断另一个线程只是告诉那个线程我要打断你被打断的线程自己决定受不受其他线程打断。也就是将打断状态改成true说明有其他线程要打断我。
所以可以在里面加一个if判断如果interrupted是真说明有其他线程要打断我所以我自己结束好了。
打断park线程
打断 park 线程, 不会清空打断状态也就是打断状态是true
例如下面的代码主线程休眠之后打断park线程
private static void test3() throws InterruptedException {Thread t1 new Thread(() - {log.debug(park...);LockSupport.park();log.debug(unpark...);log.debug(打断状态{}, Thread.currentThread().isInterrupted());}, t1);t1.start();sleep(0.5);t1.interrupt();
}
输出 21:11:52.795 [t1] c.TestInterrupt - park... 21:11:53.295 [t1] c.TestInterrupt - unpark... 21:11:53.295 [t1] c.TestInterrupt - 打断状态true 如果打断标记已经是 true, 则 park 会失效
private static void test4() {Thread t1 new Thread(() - {for (int i 0; i 5; i) {log.debug(park...);LockSupport.park();log.debug(打断状态{}, Thread.currentThread().isInterrupted());}});t1.start();sleep(1);t1.interrupt();
}输出
21:13:48.783 [Thread-0] c.TestInterrupt - park...
21:13:49.809 [Thread-0] c.TestInterrupt - 打断状态true
21:13:49.812 [Thread-0] c.TestInterrupt - park...
21:13:49.813 [Thread-0] c.TestInterrupt - 打断状态true
21:13:49.813 [Thread-0] c.TestInterrupt - park...
21:13:49.813 [Thread-0] c.TestInterrupt - 打断状态true
21:13:49.813 [Thread-0] c.TestInterrupt - park...
21:13:49.813 [Thread-0] c.TestInterrupt - 打断状态true
21:13:49.813 [Thread-0] c.TestInterrupt - park...
21:13:49.813 [Thread-0] c.TestInterrupt - 打断状态true
清除打断标记
可以使用 Thread.interrupted() 清除打断状态清除打断状态就是让打断状态变成false意思是这个线程没有被打断
不推荐使用的方法
这些方法已过时容易破坏同步代码块造成线程死锁
jdk源码中也有说不推荐这些方法
stop()停止线程运行suspend()挂起暂停线程运行resume() 恢复线程运行
守护线程
默认情况下Java 进程需要等待所有线程都运行结束才会结束。
有一种特殊的线程叫做守护线程只要其它非守护线程运行结束了即使守护线程的代码没有执行完也会强制结束。
守护线程的例子
java的垃圾回收器线程就是一种守护线程。Tomcat 中的 Acceptor 和 Poller 线程都是守护线程所以 Tomcat 接收到 shutdown 命令后不会等待它们处理完当前请求
将某个线程设置为守护线程的方法
thread.setDaemon(true);
例
log.debug(开始运行...);Thread t1 new Thread(() - {log.debug(开始运行...);sleep(2);log.debug(运行结束...);}, daemon);
// 设置该线程为守护线程
t1.setDaemon(true);
t1.start();sleep(1);
log.debug(运行结束...);
输出
08:26:38.123 [main] c.TestDaemon - 开始运行...
08:26:38.213 [daemon] c.TestDaemon - 开始运行...
08:26:39.215 [main] c.TestDaemon - 运行结束...