一、线程与进程
进程:操作系统中一个程序的执行周期称为一个进程
线程:一个程序同时执行多个任务。通常,每一个任务就称为一个线程。
多进程与多线程区别:本质区别在于,每个进程拥有自己的一整套变量,而线程则共享数据。共享变量使得线程之间的通信比进程之间通信更有效、更方便。
线程的状态
二、Java多线程的实现
1.继承Thread类实现多线程
新建一个线程最简单的方法就是直接继承Thread类,而后覆写该类中的run()方法
(1)新建一个线程,使用run方法
package Practise; class MyThread extends Thread//线程主类 { private String title; public MyThread(String title) { this.title=title; } public void run() {//所有线程从这里开始执行 for(int i=0;i<10;i++) { System.out.println(this.title+",i="+i); } } } public class Test1 { public static void main(String[] args) { MyThread myThread1=new MyThread("thread1"); MyThread myThread2=new MyThread("thread2"); MyThread myThread3=new MyThread("thread3"); myThread1.run(); myThread2.run(); myThread3.run(); } }
(2)启动多线程是使用start方法,不是run方法
public class Test1 { public static void main(String[] args) { MyThread myThread1=new MyThread("线程1"); MyThread myThread2=new MyThread("线程2"); MyThread myThread3=new MyThread("线程3"); myThread1.start(); myThread2.start(); myThread3.start(); } }多线程每次执行的结果都不同
2.Runnable()接口实现多线程
Thread类的核心功能是进行线程的启动。如果一个类为了实现多线程直接去继承Thread类就会有但继承局限。在java中又提供有另外一种实现模式:Runnable接口。
(1)利用Runnable接口来实现线程主体类
class MyThread implements Runnable{ private String title; public MyThread(String title ) { // TODO Auto-generated constructor stub this.title=title; } @Override public void run() { // TODO Auto-generated method stub for(int i=0;i<10;i++) { System.out.println(this.title+",i="+i); } } } public class Test1 { public static void main(String[] args) { MyThread myThread1=new MyThread("线程1"); MyThread myThread2=new MyThread("线程2"); MyThread myThread3=new MyThread("线程3"); new Thread(myThread1).start(); new Thread(myThread2).start(); new Thread(myThread3).start();//启动多线程 } }
(2)使用匿名内部类进行Runnable对象创建
public class Test1 { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub System.out.println("Hello World"); } }).start(); } }
(3)使用Lamdba表达式进行Runnable对象创建
public class Test1 { public static void main(String[] args) { Runnable runnable=()->System.out.println("Hello world"); new Thread(runnable).start(); } }
(4)Thread与Runnable区别
1)Runnable实现多线程可以避免单继承局限
2)在定义Thread类时,Thread类是Runnable的接口子类,因此在实现Thread类时,一定覆写了Runnable接口的run方法
3)使用Runnable实现的多线程的程序类可以更好的描述出程序共享的概念
线程类的继承结构——代理模式
使用Thread实现数据共享
启动三个线程实现卖票处理。结果变为了卖各自的票
class MyThread extends Thread { private int ticket=10; public void run() { while(this.ticket>0) { System.out.println("剩余票数"+this.ticket--); } } }
public class Test1 { public static void main(String[] args) { System.out.println("用Thread实现数据共享"); new MyThread().start(); new MyThread().start(); new MyThread().start(); } }
而使用Runnable实现共享
Runnable实现的多线程的程序类可以更好的描述出程序共享的概念
class MyThread2 implements Runnable { private int ticket=10; public void run() { while(this.ticket>0) { System.out.println("剩余票数"+this.ticket--); } } } public class Test1 { public static void main(String[] args) { System.out.println("使用Runnable实现共享"); MyThread2 mThread2=new MyThread2(); new Thread(mThread2).start(); new Thread(mThread2).start(); } }
3.Callable实现多线程
由于Runnable中的run()方法没有返回值,它的设计也遵循了主方法的设计原则:线程开始了就别回头。但是很多时候需要一些返回值,例如某些线程执行完成后可能带来一些返回结果,这种情况下就只能利用Callable来实现多线程
(1)使用Callable定义线程主体类
package Practise; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; class MyThread implements Callable<String> { private int ticket=10; public String call() throws Exception { while(this.ticket>0) { System.out.println("剩余票数"+this.ticket--); } return "票卖完了"; } } public class Test1 { public static void main(String[] args) throws InterruptedException, ExecutionException { FutureTask<String> task=new FutureTask<>(new MyThread()); new Thread(task).start(); new Thread(task).start(); System.out.println(task.get()); } }