线程与进程
在我们学习线程之前先来了解一下关于线程的一些知识
什么是进程
我们经常使用的软件他就是一个进程,一个正在运行的软件就是一个进程。
例如:一个工厂就相当于我们的一个进程。
什么是线程
进程中的一个一个独立的执行路径
例如:一个工人就是我们一个工厂中的一个线程
什么是并行
两个或多个任务在同一时间执行
例如:两个人比赛跑步他们同时出发这就相当于我们说的并行
什么是并发
两个或者多个任务在同一时间段执行
例如:两个人跑步一个人8:30出发另一个8:35,我们可以说他们在8:30到8:40这一段时间并发
Thread类介绍
我们学习线程需要用到一些类,我先来为大家介绍一下这个类里面的常用方法
构造方法介绍 Thread() 创建一个线程,线程执行的程序为自己的run方法 Thread(Runnable taret) 创建一个线程,参数为Runnable接口的实现类,开启线程运行的是这个接口的实现类里面重写的run方法 Threable(Runnable treet String name)
创建一个线程,运行的为Runnable实现类里面重写的run方法,name参数是为该线程名字
常用方法介绍 static Thread currentThread()
返回执行这一段程序的线程对象 String getName() 返回这个线程的名字 void run() 开启一个线程,这个线程就是执行run方法里面的代码,如果创建对象是传入一个Runnable对象,那么开启一个线程执行的就是Runnable实现类里面的重写的run方法 void setName() 修改该线程的名字 void setPriority(int i) 设置该线程的优先级 static void sleep(long millis) 使当前这个线程停止运行,括号里面的参数为暂停运行的时间,以毫秒为单位 void start() 开启一个线程
如何创建一个线程
创建线程有两种方式 注意:当我们主方法运行时java虚拟机会默认帮我们开一个主线
方式一:定义一个类继承Thread
重写run方法,把线程要运行的代码写入run方法中
创建Thread子类对象,调用start方法
public class Test01 { public static void main(String[] args){ //创建Thread的子类 MyThread myThread = new MyThread(); //开启一个线程 myThread.start(); //for循环100次 for (int i = 0; i < 100; i++) { //打印出运行这个代码的线程名字和循环的次数 注意:这个for循环是在主方法里面,运行这个for循环的是主线程 System.out.println(Thread.currentThread().getName()+" "+i); } } } //创建一个类,继承Thread class MyThread extends Thread{ @Override //重写run方法,把线程要运行的代码写进这个run方法, 运行这个for循环的是新开的线程 public void run() { //for循环100次 for (int i = 0; i < 100; i++) { //打印出运行这个代码的线程名字和循环的次数 System.out.println(Thread.currentThread().getName()+" "+i); } } }
运行结果如下
注意:如果你运行的结果和我的结果不一样,不要觉得奇怪,因为线程的执行是不一定的,是看哪一个线程抢到了资源谁执行,如果你运行的代码总是一个for循环先执行完然后再执行另一个for循环,你可以适当增加for循环次数,或者多运行几次。线程的运行是和电脑有关系。
方式二:定义一个类实现Runnable接口重写run方法
创建Thread类对象,创建Runnable实现类对象作为次数传入到Thread类的构造方法里面
调用Thread类对象的start方法开启一个线程
public class Test02 { public static void main(String[] args){ //创建Runnable实现类对象 MyRunnable myRunnable = new MyRunnable(); //创建一个Thread类把Runnable实现类的对象作为参数传入Thread的构造方法中 Thread thread = new Thread(myRunnable); //开启一个线程 thread.start(); //在主方法里面for循环100次 注意:这个for循环是在主方法里面,运行这个for循环的是主线程 for (int i = 0; i < 100; i++) { //输出打印当前线程名字,打印循环次数 System.out.println(Thread.currentThread().getName()+" "+i); } } } //创建一个类,继承Runnable接口 class MyRunnable implements Runnable{ @Override //重写run方法,方法里面为此线程要执行的代码 public void run() { //for循环100次 运行个run方法的是新开的线程 for (int i = 0; i < 100; i++) { //输出打印当前线程名字,打印循环次数 System.out.println(Thread.currentThread().getName()+" "+i); } } }
运行结果如下 注意:线程运行的结果不一定,线程运行的快慢和电脑有关
实现Runnable接口的好处
屏蔽了java单继承的局限性
可以更好的实现数据共享
为线程池提供了前提条件
将线程和任务进行分离,降低了线程的耦合性
方式二用匿名内部类实现
public class Test03 { public static void main(String[] args){ //创建一个Thread对象 匿名内部类实现Runnable接口 Thread thread = new Thread(new Runnable() { @Override public void run() { //for循环100次 运行个run方法的是新开的线程 for (int i = 0; i < 100; i++) { //输出打印当前线程名字,打印循环次数 System.out.println(Thread.currentThread().getName()+" "+i); } } }); //开启一个线程 thread.start(); //在主方法里面for循环100次 注意:这个for循环是在主方法里面,运行这个for循环的是主线程 for (int i = 0; i < 100; i++) { //输出打印当前线程名字,打印循环次数 System.out.println(Thread.currentThread().getName()+" "+i); } } }
方式二用lambda表达式实现
public class Test04 { public static void main(String[] args){ //创建一个Thread对象 因为Runnable是一个接口并且只有一个抽象方法,符合lambda表达式条件所以可以用lambda表达式现实 Thread thread = new Thread(()->{ //for循环100次 运行个run方法的是新开的线程 for (int i = 0; i < 100; i++) { //输出打印当前线程名字,打印循环次数 System.out.println(Thread.currentThread().getName()+" "+i); } }); //开启一个线程 thread.start(); //在主方法里面for循环100次 注意:这个for循环是在主方法里面,运行这个for循环的是主线程 for (int i = 0; i < 100; i++) { //输出打印当前线程名字,打印循环次数 System.out.println(Thread.currentThread().getName()+" "+i); } } }