JUC学习笔记——进程与线程( 五 )


// 首先我们采用start:start方法是启动该线程,线程开始运行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.start();log.debug("do other things ...");}// 然后我们直接使用run方法:run方法是调用该线程的run方法,实际是main线程在运行t1线程的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 ...");}同时我们可以通过查看线程状态来判断start和run的区别:
// 这里我们仅对start判断public static void main(String[] args) {Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug("running...");}};System.out.println(t1.getState());t1.start();System.out.println(t1.getState());}// 我们可以注意到main状态从就绪状态切换为RunnableNEWRUNNABLE03:45:12.255 c.Test5 [t1] - running...所以我们给出小结:

  • 直接调用 run 是在主线程中执行了 run,没有启动新的线程
  • 使用 start 是启动新的线程,通过新的线程间接执行 run 中的代码
sleep 与 yield我们首先给出sleep的相关解释:
  • 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
  • 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
  • 睡眠结束后的线程未必会立刻得到执行
  • 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性。其底层还是sleep方法
  • 在循环访问锁的过程中,可以加入sleep让线程阻塞时间,防止大量占用cpu资源
我们再给出yield的相关解释:
  • 调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程;具体的实现依赖于操作系统的任务调度器
  • 加入当前线程中只有这一个方法,那么停止该方法执行后仍旧执行该方法
我们采用代码来进行展示:
/*sleep状态转换:我们运行下面代码后可以看到其t1状态从就绪状态到Runnable到Timed Waiting*/public static void main(String[] args) {Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug("running...");try {Thread.sleep(2000);} catch (InterruptedException e) {log.debug("wake up...");e.printStackTrace();}}};System.out.println(t1.getState());t1.start();System.out.println(t1.getState());Thread.sleep(2000);System.out.println(t1.getState());}/*sleep打断睡眠线程,抛出异常:注意当睡眠时抛出异常后该程序的打断状态为false*/ public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread("t1") {@Overridepublic void run() {log.debug("enter sleep...");try {Thread.sleep(2000);} catch (InterruptedException e) {log.debug("wake up...");e.printStackTrace();}}};t1.start();Thread.sleep(1000);log.debug("interrupt...");t1.interrupt();}// 输出结果为:03:47:18.141 c.Test7 [t1] - enter sleep...03:47:19.132 c.Test7 [main] - interrupt...03:47:19.132 c.Test7 [t1] - wake up...java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at cn.itcast.test.Test7$1.run(Test7.java:14)/*sleep采用TimeUnit的方法更具有代码可读性*/@Slf4j(topic = "c.Test8")public class Test8 {public static void main(String[] args) throws InterruptedException {log.debug("enter");TimeUnit.SECONDS.sleep(1);log.debug("end");//Thread.sleep(1000);}}/*yield简单测试:我们需要在Linux虚拟机中使用单核cpu来处理该代码,下面我们同时使用一个cpu处理两个进程*/@Slf4j(topic = "c.TestYield")public class TestYield {public static void main(String[] args) {Runnable task1 = () -> {int count = 0;for (;;) {System.out.println("---->1 " + count++);}};Runnable task2 = () -> {int count = 0;for (;;) {Thread.yield();System.out.println("---->2 " + count++);}};Thread t1 = new Thread(task1, "t1");Thread t2 = new Thread(task2, "t2");t1.start();t2.start();}}// 我们会发现task1的count数更多,因为轮到task2时,它会调用yield可能会导致当前线程停止从而去运行另一个线程---->1 119199---->2 101074

经验总结扩展阅读