上课学的java忘得差不多了,再看看多线程吧…
java语言实现了多线程机制,为什么不说是多进程的,因为进程概念是操作系统层面上的,不管OS有没有实现线程,进程都是资源调度的基本单位,线程只拥有很少的一部分资源,用于保证自己的正常运行。在一些没有实现多进程的系统上,就更不存在线程了。在多进程的系统中比如Windows操作系统,进程间的内存空间是互相独立的,数据不能直接共享,它的异步协作方式由进程中的线程来完成,这些线程共享进程所属内存来完成异步协作,java在这种操作系统上,表现的就是单进程多线程的方式。
-
线程的生命周期
一个线程被实例化完成,到这个线程销毁,这整个过程。
-
线程的状态及状态转换
– 创建态(新生态)
– 就绪态
– 运行态
– 阻塞态
– 销毁态(死亡态)
这张图是我在听一个网课(千锋教育)时截的图,不是自己画的,老师讲的很棒。
-
线程的创建
package thread; public class ThreadCreate { public static void main(String[] args) { //1.继承Thread类,实现一个线程子类(自定义线程类) MyThread mt = new MyThread(); mt.start(); //2.通过Runnable 接口 /*Runnable r = new Runnable() { public void run() { } };*/ //通过Runnable接口,使用lamada表达式 Runnable r2 = ()->{ for(int i = 0; i < 10; i++) { System.out.println("线程2执行" + i); } }; Thread t2 = new Thread(r2); t2.start(); System.out.println("主线程执行..."); } } class MyThread extends Thread{ /** * 重写run方法 * 将需要并发执行的任务写到run方法中 */ @Override public void run() { for(int i = 0; i < 10; i++) { System.out.println("MyThread线程中的逻辑" + i); } } }
需要注意的是mt.start();
这个start方法是必要的,用来开启一个新的线程,来执行run中的逻辑;如果直接调用run()方法,则不会进入就绪状态,直接进入运行状态,没有并发。
-
线程的命名
package thread; public class ThreadName { public static void main(String[] args) { //1.使用Thread类中的setName方法 Thread thread = new Thread(); thread.setName("线程1"); //2.实例化一个线程的时候,通过构造方法对线程命名 Thread thread2 = new Thread("线程2"); Thread thread3 = new Thread(()-> {}, "线程3"); //3.使用自定义的线程类,在实例化线程对象的同时,进行命名 Thread myThread2 = new Thread("Mythread"); System.out.println(thread.getName()); System.out.println(thread2.getName()); System.out.println(thread3.getName()); System.out.println(myThread2.getName()); } } class MyThread2 extends Thread{ public MyThread2() {} public MyThread2(String name) { // super(name); this.setName(name); } }
运行结果:
线程1
线程2
线程3
Mythread -
线程的休眠
就是sleep()方法,它使线程进入阻塞状态,当给定时间到了以后,将恢复就绪状态,如果分配到了CPU,转换为执行状态,时间单位是毫秒,没再写新的线程,把Mythread2的run方法重写了一下。
package thread; public class ThreadName { public static void main(String[] args) { //threadName(); threadSleep(); } private static void threadSleep() { Thread mThread2 = new MyThread2(); mThread2.start(); } private static void threadName() { //1.使用Thread类中的setName方法 Thread thread = new Thread(); thread.setName("线程1"); //2.实例化一个线程的时候,通过构造方法对线程命名 Thread thread2 = new Thread("线程2"); Thread thread3 = new Thread(()-> {}, "线程3"); //3.使用自定义的线程类,在实例化线程对象的同时,进行命名 Thread myThread2 = new Thread("Mythread"); System.out.println(thread.getName()); System.out.println(thread2.getName()); System.out.println(thread3.getName()); System.out.println(myThread2.getName()); } } class MyThread2 extends Thread{ public MyThread2() {} public MyThread2(String name) { // super(name); this.setName(name); } @Override public void run() { for(int i = 0; i < 10; i++) { try { Thread.sleep(1000); //线程休眠1秒钟 System.out.println(i); } catch (InterruptedException e) { e.printStackTrace(); } } } }
-
线程的优先级
设置的优先级,只是修改这个线程可以抢到CPU时间片的概率并不是优先级高的线程一定能抢到CPU,优先级的设置,是一个0-10的整数;如果未设置,优先级默认为5。
package thread; public class ThreadName { public static void main(String[] args) { threadPriority(); } private static void threadPriority() { Runnable r = ()->{ for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); } }; Thread r1 = new Thread(r, "线程1"); Thread r2 = new Thread(r, "线程2"); //设置优先级 r1.setPriority(1); r2.setPriority(10); r1.start(); r2.start(); } }
-
线程礼让
让当前的运行态的线程释放自己的CPU资源,由运行状态,返回就绪态
执行yield方法,当前正在执行的线程让出CPU,成为就绪态,重新等待CPU分配。
需要注意的是就算当前线程让出CPU,它可能又会被CPU分配到资源,比如说下面的例子,当i=3 的时候,线程礼让,但是这个线程礼让后可能又会分配到CPU,继续执行i=4。
package thread; public class ThreadName { public static void main(String[] args) { threadYield(); } private static void threadYield() { Runnable r = ()->{ for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); if(i == 3) { Thread.yield(); //线程礼让 } } }; Thread r1 = new Thread(r); Thread r2 = new Thread(r); r1.start(); r2.start(); } }
一种不出乎意料的结果:
Thread-0:0
Thread-1:0
Thread-1:1
Thread-1:2
Thread-1:3
Thread-0:1
Thread-0:2
Thread-0:3
Thread-1:4
Thread-1:5
Thread-1:6
Thread-1:7
Thread-1:8
Thread-0:4
Thread-0:5
Thread-0:6
Thread-0:7
Thread-1:9
Thread-0:8
Thread-0:9