概述
- 进程:
1:引入原因:为描述并发下程序的执行情况。
2:定义:进程是正在运行的程序。是系统进行资源分配的调用的独立单位,每一个进程都有它自己的内存空间和系统资源。
3:特征:并发性 / 独立性 / 异步性 / 动态性 / 结构特性:进程=程序段+数据段+PCB - 线程:
是进程中的单个顺序控制流,是一条执行路径。 - 进程和程序的区别与联系
①进程是一个动态的概念;程序是一个静态的概念;
②进程具有并发性,而程序没有;
③进程是资源分配和处理机调度的独立单位,其并发性受系统制约;
④一个程序,多次执行,对应多个进程;不同的进程可以包含同一程序。
实现多线程
继承Thead方法实现多线程
public class Thread
extends Object
implements Runnable
- 线程是程序中执行的线程。 Java虚拟机允许应用程序同时执行多个执行线程。
创建一个新的执行线程有两种方法:
-
一:是将一个类声明为Thread的子类。 这个子类应该重写Thread类的方法run。 然后可以分配并启动子类的实例。
1:创建Mythead继承Thread类
2:重写方法run
3:创建Mythread对象
4:启动线程 -
需要用到的两个Teread类的方法
1:public void run() 用来封装被线程重写的方法。 Thread的Thread应该覆盖此方法。
2:public void start()导致此线程开始执行; Java虚拟机调用此线程的run方法。结果是两个线程同时运行:当前线程(从调用返回到start方法)和另一个线程(执行其run方法)。 不止一次启动线程是不合法的。 特别地,一旦线程完成执行就可能不会重新启动。
异常 :IllegalThreadStateException - 如果线程已经启动。 -
代码演示:
public class Mythread extends Thread {
@Override
public void run() {
for (int i = 0; i <50; i++) {
System.out.println(i);
}
}
}
public class MytheadDemo {
public static void main(String[] args) {
Mythread thread1=new Mythread();
Mythread thread2=new Mythread();
thread1.start();
thread2.start();
}
}
- currentThread()
public static Thread currentThread()返回对当前正在执行的线程对象的引用。
public class MytheadDemo {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
}
}
线程的调度(优先级设置)
线程调度的两种模型:
1:分时调度模型:就绪队列的线程轮流使用CPU,平均分配时间片
2:抢占式调度模型:优先级高的优先占用CPU,优先级相同的抢占式占用CPU。优先级高的获得的时间片相对多。
-
java中使用setPriority/getPriority来设置/得到线程的优先级
-
public final void setPriority(int newPriority)
更改此线程的优先级。
首先调用这个线程的checkAccess方法,没有参数。 这可能会导致投掷SecurityException 。
异常 :
IllegalArgumentException - 如果优先级不在 MIN_PRIORITY(1)到 MAX_PRIORITY (10)。
SecurityException - 如果当前线程不能修改此线程。 -
public final int getPriority()
返回此线程的优先级。
上图可以看到线程最大优先级是10,最小1,默认5。
public static void main(String[] args) {
Mythread mythread1=new Mythread();
Mythread mythread2=new Mythread();
System.out.println(mythread1.getPriority());
mythread1.setPriority(Thread.MIN_PRIORITY);
}
线程控制三种方法
-
join
public final void join(long millis) throws InterruptedException
等待这个线程死亡的时间为millis毫秒。 0的超时意味着永远等待。 -
public static void sleep(long millis)throws InterruptedException
使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。 线程不会丢失任何显示器的所有权。 -
public final void setDaemon(boolean on)
将此线程标记为守护线程或用户线程。 当运行的唯一线程都是守护进程线程时,Java虚拟机将退出。 线程启动前必须调用此方法。
守护线程守护的是主线程,所以当主线程结束,守护线程也会迅速完毕(不是立即)。
public static void main(String[] args) {
Mythread mythread1=new Mythread();
Mythread mythread2=new Mythread();
Thread.currentThread().setName("主线程");//当前线程为主线程,这里是设置一个名字
//设置mythread1/2为守护线程
mythread1.setDaemon(true);
mythread2.setDaemon(true);
mythread1.start();
mythread2.start();
mythread1.run();
mythread2.run();
for (int i = 0; i <10 ; i++) {
System.out.println(Thread.currentThread().getName()+i);
}//这个结束后主线程就结束了,守护线程也迅速结束
}
线程的生命周期
实现 Runnable接口方式实现多线程
自定义类实现Runnable接口,将自定义类的对象传入Thread构造函数的参数。
- Thread构造函数
Thread(Runnable target, String name)
分配一个新的 Thread对象
好处是不影响自定义类的继承,自定义类可以作为同一个资源供多个线程使用。
代码示范:
public class Mythread implements Runnable {
@Override
public void run() {
for (int i = 0; i <50; i++) {
System.out.println(i);
}
}
}
public class MytheadDemo {
public static void main(String[] args) {
Mythread mythread1=new Mythread();
Thread thread1=new Thread(mythread1,"线程1");
thread1.run();
}
}
线程同步
- 案例练习:卖票
public class SellTickes implements Runnable {
private int tickes;
public SellTickes() {
this.tickes=100;
}
public int getTickes() {
return tickes;
}
@Override
public void run() {
if (this.tickes>0){
this.tickes--;
}
}
}
public class SellTickesDemo {
public static void main(String[] args) {
SellTickes alltic=new SellTickes();
Thread tic1=new Thread(alltic,"售票口1");
Thread tic2=new Thread(alltic,"售票口1");
Thread tic3=new Thread(alltic,"售票口1");
tic1.start();
tic2.start();
tic3.start();
int ticket;
while (true){
tic1.run();
tic2.run();
tic3.run();
ticket=alltic.getTickes();
System.out.println(ticket);
}
}
}
上面代码,如果在加上Sleep每个进程休眠一段时间,会导致一张票被埋多次,票出现负数。
- 同步代码块解决多个线程同时访问一段代码