实现线程的三种方式
1、继承Thread类,重写里面的run方法
public class MyThread extends Thread{@Overridepublic void run() {System.out.println("threadName:"+Thread.currentThread().getName());}}/*** 方式一:继承Thread类,重写里面的run方法*/@Testvoid thread1(){new MyThread().start();}
2、实现 Runnable 接口 这里直接用匿名内部类 实现了
@Testvoid thread2(){new Thread(()->{System.out.println("threadName:"+Thread.currentThread().getName());},"thread1").start();}
3、实现 Callable接口 然后 放到Thread 中 这样能拿到一个结果
/*** 方式三:实现 Callable接口 然后 放到Thread 中 这样能拿到一个结果* @throws ExecutionException* @throws InterruptedException* @throws TimeoutException*/@Testvoid thread3() throws ExecutionException, InterruptedException, TimeoutException {//Callablefinal FutureTask<String> futureTask = new FutureTask<>(() -> {Thread.sleep(TimeUnit.SECONDS.toMillis(2));System.out.println("ThreadName:" + Thread.currentThread().getName());return "success";});new Thread(futureTask).start();// 调用get 会阻塞在这里 ,成功拿到结果才行final String result = futureTask.get();System.out.println(result);System.out.println("end");}
注:另外还可以通过线程池创建线程
main方法中线程执行分析
main方法 中 流程:进程-开启一个主线程-主线程又开启一个子线程
注:主线程执行完后 子线程会继续执行。但是用@Test 注解 实现就不行。
原因:@Test 注解时,JUnit会自动创建一个测试线程来运行测试方法,并在测试方法执行完毕后立即终止该线程,而不管该线程是否已经执行完毕。因此,在使用@Test注解时,子线程可能无法执行完毕,因为测试线程已经被终止了
流程:进程-开启一个主线程-主线程又开启一个子线程
public static void main(String[] args) {new Thread(()->{for (int i = 0; i <50; i++) {try {Thread.sleep(TimeUnit.SECONDS.toMillis(1));} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程:"+Thread.currentThread().getName()+",正在干活"+",count:"+(i+1));}}).start();for (int i = 0; i < 40; i++) {try {Thread.sleep(TimeUnit.SECONDS.toMillis(1));} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程:"+Thread.currentThread().getName()+",正在干活"+",count:"+(i+1));}}
Thread方法
start()
这个就是启动线程的方法,他和run方法的区别是,start是通过本地方法private native void start0();
(底层JVM调用,c/c++实现的)开启新的线程然后执行run方法。
而run方法本身就是一个普通方法。
run()
本身就是一个普通方法,如果直接调用它。比如拿刚才的例子,下面换成run方法,其实就是main线程在执行。执行完run方法里然后执行下面的,这就不是多线程了。而是一个线程在顺序执行!!!
@Testvoid mainThreadAndSonThread(){new Thread(()->{for (int i = 0; i <50; i++) {try {Thread.sleep(TimeUnit.SECONDS.toMillis(1));} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程:"+Thread.currentThread().getName()+",正在干活"+",count:"+(i+1));}}).run();for (int i = 0; i < 40; i++) {try {Thread.sleep(TimeUnit.SECONDS.toMillis(1));} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程:"+Thread.currentThread().getName()+",正在干活"+",count:"+(i+1));}}
守护线程
1、用户线程
即工作线程,线程执行完即结束了
2、守护线程
一般是为了工作线程服务的,当所有用户线程结束时,守护线程自动结束
3、常见的守护线程:垃圾回收机制
下面例子:自己开启一个守护线程,然后一直监听工作线程,等工作线程工作完成后,守护线程自己也就结束了。
@Testvoid testDaemon(){final Thread thread = new Thread(() -> {while (true){try {Thread.sleep(TimeUnit.SECONDS.toMillis(1));} catch (InterruptedException e) {e.printStackTrace();}System.out.println("ThreadName:"+Thread.currentThread().getName()+" 正在监听工作线程:");}},"son Thread");//将 son Thread 线程 设置为守护线程 当main线程结束 sonThread 线程就结束thread.setDaemon(true);thread.start();for (int i = 0; i < 10; i++) {try {Thread.sleep(TimeUnit.SECONDS.toMillis(1));} catch (InterruptedException e) {e.printStackTrace();}System.out.println("线程:"+Thread.currentThread().getName()+",正在干活"+",count:"+(i+1));}}