并发与并行
并发:指两个或多个事件在同一时间段内发生。
并行:指两个或多个事件在同一时刻发生(同时发生)。
进程与线程
进程:
是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
线程:
线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
简而言之:
一个程序运行后至少有一个进程,一个进程中可以包含多个线程。
线程调度
分时调度:
所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。
抢占式调度:
优先让优先级高的銭程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。
Java中的主线程
主线程:执行主(main)方法的线程。
单线程
单线程:Java程序中,只有一个线程,执行从main方法开始,从上到下的执行。
举例
public classStudent {public static voidmethod1() {for (int i = 0; i < 5; i++) {
System.out.println(“我正在执行Student的方法1”);
}
}public static voidmethod2() {for (int i = 0; i < 5; i++) {
System.out.println(“我正在执行Student的方法2”);
}
}publicStudent() {
}
}
public classDemo01MainThread {public static voidmain(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 extendsThread {/*** 重写Thread类的run方法,设置任务*/@Overridepublic voidrun() {for (int i = 0; i < 6; i++) {
System.out.println(“我正在执行重写的run方法中的线程:” +i);
}
}
}
public classDemo02MainThread {public static voidmain(String[] args) {//创建Thread的子类对象
Thread myThread = newPerson();//调用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类的常用方法
publicString getName():获取当前线程名称。public voidstart():导致此线程开始执行;Java虚拟机调用此线程的run方法。public voidrun():此线程要执行的任务在此处定义代码。public static void sleep(longmillis):使当前正在执行的线程以指定的亳秒数暂停(暂时停止执行)。public static Thread currentThread()返回对当前正在执行的线程对象的引用。
getName()方法、start()方法、run()方法
public class MyThread extendsThread {
@Overridepublic voidrun() {//此线程要执行的任务
}
}
public classDemo01MyThread {public static voidmain(String[] args) {
MyThread myThread1= newMyThread();
myThread1.start();
String run1Name=myThread1.getName();
MyThread myThread2= newMyThread();
myThread2.start();
String run2Name=myThread2.getName();
MyThread myThread3= newMyThread();
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 extendsThread {
@Overridepublic voidrun() {//此线程要执行的任务
System.out.println(Thread.currentThread());
}
}
public classDemo02MyThread {public static voidmain(String[] args) {
MyThread myThread1= newMyThread();
myThread1.start();
MyThread myThread2= newMyThread();
myThread2.start();
MyThread myThread3= newMyThread();
myThread3.start();
}
}
控制台输出:
Thread[Thread-0,5,main]
Thread[Thread-2,5,main]
Thread[Thread-1,5,main]
了解一下setName()方法:设置线程的名称
public classDemo03MyThread {public static voidmain(String[] args) {
MyThread myThread= newMyThread();
myThread.setName(“李华”);
myThread.start();
}
}
控制台输出:
Thread[李华,5,main]
sleep()方法
public class MyThread2 extendsThread {
@Overridepublic voidrun() {//此线程要执行的任务
for (int i = 0; i < 11; i++) {try{//参数为毫秒
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.print(“第” + i + “秒 “);
}
}
}
public classDemo01MyThread2 {public static voidmain(String[] args) {
MyThread2 thread2= newMyThread2();
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 implementsRunnable {
@Overridepublic voidrun() {//在实现类中重写 Runnable接口的run方法,设置线程任务。
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName()+ ” ~~~~~~~~~ ” +i);
}
}
}
public classDemoRunnable {public static voidmain(String[] args) {//创建一个 Runnable接口的实现类对象。
MyRunnable myRunnable = newMyRunnable();//创建Thread类对象,构造方法中传递 Runnable接口的实现类对象。
Thread thread = newThread(myRunnable);//调用 Threads类中的 start方法,开启新的线程执行run方法
thread.start();//main方法线程
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName()+ ” ~~~~~~~~~ ” +i);
}
}
}
控制台输出:
main~~~~~~~~~ 0Thread-0 ~~~~~~~~~ 0main~~~~~~~~~ 1Thread-0 ~~~~~~~~~ 1Thread-0 ~~~~~~~~~ 2main~~~~~~~~~ 2
使用Runnable相比Thread有哪些优势
适合多个相同的程序代码的线程去共享同一个资源。
可以避兔Java中的单继承的局限性。
増加程序的健壮性,实现解耦(把设置线程任务和开启线程分开)操作,代码可以被多个线程共享,代码和线程独立。
线程池只能放入实现 Runable或 Callable类线程,不能直接放入继承 Thread的类。
内部类实现创建多线程
public class MyRunnable implementsRunnable {
@Overridepublic voidrun() {//在实现类中重写 Runnable接口的run方法,设置线程任务。
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName()+ ” ~~~~~~~~~ ” +i);
}
}
}
public classDemoSimpleThread {public static voidmain(String[] args) {//创建一个 Runnable接口的实现类对象。
MyRunnable myRunnable = newMyRunnable();newThread(myRunnable) {
@Overridepublic voidrun() {
System.out.print(“匿名内部类的方式实现多线程的创建:”);
System.out.println(Thread.currentThread().getName()+ “线程”);
}
}.start();//main线程
System.out.println(“main线程”);
}
}
控制台输出:
main线程
匿名内部类的方式实现多线程的创建:Thread-0线程