并发与并行
并发:指两个或多个事件在同一时间段内发生。
并行:指两个或多个事件在同一时刻发生(同时发生)。
进程与线程
进程:
是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
线程:
线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
简而言之:
一个程序运行后至少有一个进程,一个进程中可以包含多个线程。
线程调度
分时调度:
所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。
抢占式调度:
优先让优先级高的銭程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。
Java中的主线程
主线程:执行主(main)方法的线程。
单线程
单线程:Java程序中,只有一个线程,执行从main方法开始,从上到下的执行。
举例
public class Student { public static void method1() { for (int i = 0; i < 5; i++) { System.out.println("我正在执行Student的方法1"); } } public static void method2() { for (int i = 0; i < 5; i++) { System.out.println("我正在执行Student的方法2"); } } public Student() { } }
public class Demo01MainThread { public static void main(String[] args) { Student.method1(); Student.method2(); } }
控制台输出: 我正在执行Student的方法1 我正在执行Student的方法1 我正在执行Student的方法1 我正在执行Student的方法1 我正在执行Student的方法1 我正在执行Student的方法2 我正在执行Student的方法2 我正在执行Student的方法2 我正在执行Student的方法2 我正在执行Student的方法2 从控制台输出可以知道,程序从上到下的执行,从方法1开始执行,到方法2开始执行。
多线程
创建多线程程序的第一种方式
创建Thread类的子类
java.lang.Thread类:是描述线程的类,我们想要实现多线程程序,就必须继承Thread类
实现步骤:
- 创建一个 Thread类的子类。
- 在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么)。
- 创建Thread类的子类对象。
- 调用Thread类中的start方法,开启新的线程,执行run方法
void start()使该线程开始执行。Java虚拟机调用该线程的run方法。结果是两个线程并发地运行;当前线程(main线程)和另一个线程(创建的新线程,执行其run方法)。多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。Java程序属于抢占式调度,哪个线程的优先级高,哪个线程优先执行;同一个优先级,随机选择一个执行。
例子:
public class Person extends Thread { /** * 重写Thread类的run方法,设置任务 */ @Override public void run() { for (int i = 0; i < 6; i++) { System.out.println("我正在执行重写的run方法中的线程:" + i); } } }
public class Demo02MainThread { public static void main(String[] args) { // 创建Thread的子类对象 Thread myThread = new Person(); // 调用Thread类中的start方法,开启新的线程,执行run方法 myThread.start(); // main方法中的要执行的线程 for (int i = 0; i < 6; i++) { System.out.println("我正在执行main方法的线程:" + i); } } }
控制台输出: 我正在执行main方法的线程:0 我正在执行main方法的线程:1 我正在执行重写的run方法中的线程:0 我正在执行main方法的线程:2 我正在执行重写的run方法中的线程:1 我正在执行重写的run方法中的线程:2 我正在执行重写的run方法中的线程:3 我正在执行重写的run方法中的线程:4 我正在执行重写的run方法中的线程:5 我正在执行main方法的线程:3 我正在执行main方法的线程:4 我正在执行main方法的线程:5
多线程的原理
Thread类的常用方法
public String getName():获取当前线程名称。 public void start():导致此线程开始执行;Java虚拟机调用此线程的run方法。 public void run():此线程要执行的任务在此处定义代码。 public static void sleep(long millis):使当前正在执行的线程以指定的亳秒数暂停(暂时停止执行)。 public static Thread currentThread()返回对当前正在执行的线程对象的引用。
getName()方法、start()方法、run()方法
public class MyThread extends Thread { @Override public void run() { // 此线程要执行的任务 } }
public class Demo01MyThread { public static void main(String[] args) { MyThread myThread1 = new MyThread(); myThread1.start(); String run1Name = myThread1.getName(); MyThread myThread2 = new MyThread(); myThread2.start(); String run2Name = myThread2.getName(); MyThread myThread3 = new MyThread(); myThread3.start(); String run3Name = myThread3.getName(); System.out.println("线程1名称:" + run1Name); System.out.println("线程2名称:" + run2Name); System.out.println("线程3名称:" + run3Name); } }
控制台输出: 线程1名称:Thread-0 线程2名称:Thread-1 线程3名称:Thread-2
currentThread()方法
public class MyThread extends Thread { @Override public void run() { // 此线程要执行的任务 System.out.println(Thread.currentThread()); } }
public class Demo02MyThread { public static void main(String[] args) { MyThread myThread1 = new MyThread(); myThread1.start(); MyThread myThread2 = new MyThread(); myThread2.start(); MyThread myThread3 = new MyThread(); myThread3.start(); } }
控制台输出: Thread[Thread-0,5,main] Thread[Thread-2,5,main] Thread[Thread-1,5,main]
了解一下setName()方法:设置线程的名称
public class Demo03MyThread { public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.setName("李华"); myThread.start(); } } 控制台输出: Thread[李华,5,main]
sleep()方法
public class MyThread2 extends Thread { @Override public void run() { // 此线程要执行的任务 for (int i = 0; i < 11; i++) { try { // 参数为毫秒 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.print("第" + i + "秒 "); } } }
public class Demo01MyThread2 { public static void main(String[] args) { MyThread2 thread2 = new MyThread2(); thread2.start(); } }
控制台输出: 第0秒 第1秒 第2秒 第3秒 第4秒 第5秒 第6秒 第7秒 第8秒 第9秒 第10秒
创建多线程的第二种方式
实现Runnable接口,来创建多线程。
实现步骤
- 创建一个 Runnable接口的实现类。
- 在实现类中重写 Runnable接口的run方法,设置线程任务。
- 创建一个 Runnable接口的实现类对象。
- 创建Thread类对象,构造方法中传递 Runnable接口的实现类对象。
- 调用 Threads类中的 start方法,开启新的线程执行run方法
举例
// 创建一个 Runnable接口的实现类。 public class MyRunnable implements Runnable { @Override public void run() { // 在实现类中重写 Runnable接口的run方法,设置线程任务。 for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName() + " ~~~~~~~~~ " + i); } } }
public class DemoRunnable { public static void main(String[] args) { // 创建一个 Runnable接口的实现类对象。 MyRunnable myRunnable = new MyRunnable(); // 创建Thread类对象,构造方法中传递 Runnable接口的实现类对象。 Thread thread = new Thread(myRunnable); // 调用 Threads类中的 start方法,开启新的线程执行run方法 thread.start(); // main方法线程 for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName() + " ~~~~~~~~~ " + i); } } }
控制台输出: main ~~~~~~~~~ 0 Thread-0 ~~~~~~~~~ 0 main ~~~~~~~~~ 1 Thread-0 ~~~~~~~~~ 1 Thread-0 ~~~~~~~~~ 2 main ~~~~~~~~~ 2
使用Runnable相比Thread有哪些优势
- 适合多个相同的程序代码的线程去共享同一个资源。
- 可以避兔Java中的单继承的局限性。
- 増加程序的健壮性,实现解耦(把设置线程任务和开启线程分开)操作,代码可以被多个线程共享,代码和线程独立。
- 线程池只能放入实现 Runable或 Callable类线程,不能直接放入继承 Thread的类。
内部类实现创建多线程
public class MyRunnable implements Runnable { @Override public void run() { // 在实现类中重写 Runnable接口的run方法,设置线程任务。 for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName() + " ~~~~~~~~~ " + i); } } }
public class DemoSimpleThread { public static void main(String[] args) { // 创建一个 Runnable接口的实现类对象。 MyRunnable myRunnable = new MyRunnable(); new Thread(myRunnable) { @Override public void run() { System.out.print("匿名内部类的方式实现多线程的创建:"); System.out.println(Thread.currentThread().getName() + "线程"); } }.start(); // main线程 System.out.println("main线程"); } }
控制台输出: main线程 匿名内部类的方式实现多线程的创建:Thread-0线程
原文地址:https://www.cnblogs.com/liyihua/p/12209652.html