进程与线程:
进程就是在操作系统中,运行中的程序,每个程序就是一个单独的进程;在多核多线程处理器的时代,在进程运行中,通过多线程技术,为系统减少上下文消耗,提高并发量;
JAVA中实现多线程的方式:
1,Thread类实现多线程:通过继承Tread类,重写run方法来实现多线程操作;具体代码如下
1 package com.zehui.thread; 2 3 /** 4 * @Classname ThreadTest 5 * @Description TODO 6 * @Date 2020/3/4 3:19 7 * @Created by Nikla 8 */ 9 public class ThreadTest { 10 public static void main(String[] args) { 11 MyThread myThread1 = new MyThread("my1"); 12 MyThread myThread2 = new MyThread("my2"); 13 myThread1.start(); ///启动线程1 14 myThread2.start(); ///启动线程2 15 //错误,不能重复启动一个线程,否则会抛出IllegalThreadStateException 16 /*for (int i = 0; i < 10; i++) { 17 if (!myThread1.isAlive()) { 18 myThread1.start(); 19 } 20 if (!myThread2.isAlive()) { 21 myThread2.start(); 22 } 23 }*/ 24 25 } 26 } 27 28 class MyThread extends Thread { 29 public MyThread(String name) { 30 super(name); 31 } 32 33 @Override 34 public void run() { 35 try { 36 Thread.sleep(1000); 37 System.out.println(this.getName() + "running"); 38 } catch (InterruptedException e) { 39 e.printStackTrace(); 40 } 41 42 } 43 }
优点:简单方便,直接new该类对象,执行start方法就可以启动多线程
缺点:单继承局限,已继承Thread后不能继承其他类;
2,Runnable接口实现多线程:多线程执行类通过实现Runnable接口,重写run方法即可
package com.zehui.thread; /** * @Classname RunnableTest * @Description TODO * @Date 2020/3/4 3:33 * @Created by Nikla */ public class RunnableTest { public static void main(String[] args) { MyRunnable runnable = new MyRunnable("haha"); Thread mythread = new Thread(runnable); mythread.start(); } } class MyRunnable implements Runnable{ private String name; public MyRunnable(String name) { this.name = name; } public String getName() { return name; } @Override public void run() { System.out.println(this.getName()+" runnable"); } }
3,有点:取消继承Thread类的依赖(单继承的局限)
Thread与Runnable的关系:
在Thread启动多线程的时候,调用的是start方法,最后执行的是run方法;通过Thread类的构造方法,传入Runnable接口的对象是,那么接口对象被Thread对象的target属性保存,执行的strat方法的时候调用用run方法,而这个run方法去调用runnable接口子类被覆写过的run方法;
多线程开发的本质实质上是在与多个线程可以进行同一资源的抢占,Thread主要来描述线程,Runnable来描述资源
4,Callable接口
Runnable接口实现多线程,没有不能返回线程执行的结果,而Callable接口则可以返回现车执行的结果;
代码如下:
1 package com.zehui.thread; 2 3 import java.util.concurrent.Callable; 4 import java.util.concurrent.ExecutionException; 5 import java.util.concurrent.FutureTask; 6 7 /** 8 * @Classname CallableTest 9 * @Description TODO 10 * @Date 2020/3/4 3:37 11 * @Created by Nikla 12 */ 13 public class CallableTest { 14 15 public static void main(String[] args) throws ExecutionException, InterruptedException { 16 MyCallable myCallable = new MyCallable(); //新建接口子类对象 17 //FutureTask泛型类型为Callable接口的泛型类型,也即接口子类对象返回值类型 18 FutureTask<String> futureTask = new FutureTask<>(myCallable); 19 new Thread(futureTask).start(); 20 //获取线程执行结果 21 System.out.println(futureTask.get()); 22 } 23 } 24 class MyCallable implements Callable<String>{ 25 26 @Override 27 public String call() { 28 for (int i = 0; i < 10 ; i++) { 29 int x= i+1; 30 System.out.println("MyCallable 打印出 x="+ x); 31 } 32 return "MyCallable 执行完毕"; 33 } 34 }
类关系图如下:
对线程常用方法:
线程命名和取得
多线程深入话题:
优雅的停止线程:正式编写代码中,可以使用Threa.sleep(【毫秒值】);来停止线程;
后台守护线程:
守护线程:程序中,当进程内所有非守护线程执行结束后面,无论守护线程在任何状态,都会停止执行;jvm中,垃圾回收gc就是守护线程;
设置守护线程:thread.setDaemon(true);
volatile:该关键字定义的变量,在多线程环境中,线程直接操作该变量;若没有添加该关键的变量,多线程环境中,线程内操作该变量,是操作做线程内该变量的副本,操作完成后再同步到该变量中;
多线程综合案例:
数字加减:
生产电脑:
竞争抢答: