Java基础复习-多线程
本文仅对学习过程中所缺java知识点的查缺补漏复习
多线程
- 程序(program):为了完成特定任务,用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象;
- 进程(process):程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有自身的产生、存在和消亡的过程-生命周期;
- 程序是静态的,进程是动态的;
- 进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域;
- 线程(thread):进程可以进一步细化为线程,是一个程序内部的一条执行路径。
- 若一个进程同一时间并行执行多个线程,就是支持多线程的;
- 线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小;
- 一个进程中的多个线程共享相同的内存单元/内存地址空间----->它们从同一堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能就带来安全隐患;
一个Java应用程序java.exe
,至少有三个线程:main()
主线程、gc()
垃圾回收线程、异常处理线程。但是如果发生了异常,是会影响主线程的;
并行和并发
- 并行:多个CPU同时执行多个任务。比如:多个人同时做不同的事。
- 并发:一个CPU(采用时间片)同时执行多个任务。比如:秒杀、多个人做同一件事。
Java中多线程的使用
多线程的创建1:继承Thread类
方式1:继承于Thread
类
- 1.创建一个继承于
Thread
类的子类 - 2.重写
Thread
类的run()
方法:新线程要执行的操作 - 3.创建
Thread
类子类的对象 - 4.通过对象调用
start()
方法:启动当前新线程;JVM调用当前线程的run()
方法 - 注意:这里需要调用
start()
方法,不能直接调用run()
方法,调用run()
方法虽然不会报错,但是跟普通的对象调用方法就没区别了,就不会开启多线程。 - 如果需要再开启同一子类的第二个线程,需要重新
new
一个子类对象,不能用原来new
好的子类对象去再次调用start()
方法,不然会抛一个违法线程状态异常
public class MyThread extends Thread {
@Override
public void run() {
for (int i=0;i<100;i++)
if (i % 5 == 0)
System.out.println(i);
}
}
public class ThreadTest {
public static void main(String[] args){
MyThread myThread = new MyThread();
myThread.start();
for (int i=0;i<100;i++)
if (i % 5 != 0)
System.out.println("main:"+i);
}
}
Thread方法
Thread中的常用方法:
start()
:启动当前线程,调用当前线程的run()
;run()
:通常需要重写Thread
类中的此方法,将创建的线程要执行的操作声明在此方法中;currentThread()
:静态方法,返回执行当前代码的线程;etName()
:获取当前线程的名字;setName()
:设置当前线程的名字;yield()
:释放当前cpu的执行权,但是执行权可能下一刻还是轮到当前线程;join()
:在线程a中调用线程b的join()
,此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态;sleep(long millis)
:单位毫秒,令当前活动线程在指定时间段内放弃对CPU控制,使其它线程有机会被执行,时间到后重排队;isAlive()
:判断当前线程是否还活着。
线程优先级
MAX_PRIORITY:10
(最高线程优先级)MIN_PRIORITY:1
(最低线程优先级)NORM_PRIORITY:5
(默认线程优先级)getPriority()
:获取当前线程优先级;setPriority(int p)
:设置当前线程优先级- 优先级的设置在线程启动之前;
- 优先级高只是比较高概率会被执行,但不是高优先级的执行完才会执行低优先级的;
例子
三个窗口卖票1
/**
* 虽然下面这种方式可以模拟三个窗口卖100张票的场景,
* 但是可能会出现并发,线程不安全,后面将会改进,
* 这里的代码旨在模拟多线程
**/
public class Window extends Thread {
private static int ticket = 100;
@Override
public void run() {
while(true){
if(ticket > 0)
System.out.println(getName() + ":" + ticket--);
else
break;
}
}
public static void main(String[] args){
Window window1 = new Window();
Window window2 = new Window();
Window window3 = new Window();
window1.setName("线程1");
window2.setName("线程2");
window3.setName("线程3");
window1.start();
window2.start();
window3.start();
}
}
多线程的创建2:实现Runnable接口
- 创建一个实现了
Runnable
接口的类; - 实现类去实现
Runnable
中的抽象方法:run()
; - 创建实现类的对象;
- 将此对象作为参数传递到
Thread
类的构造器中,创建Thread
类的对象; - 通过
Thread
类的对象调用start()
。
public class MRunnable implements Runnable {
@Override
public void run() {
for(int i=1;i<=100;i++)
if(i % 2 == 0)
System.out.println(Thread.currentThread().getName()+":"+i);
}
public static void main(String[] args){
MRunnable mRunnable = new MRunnable();
Thread thread1 = new Thread(mRunnable);
thread1.setName("线程1");
Thread thread2 = new Thread(mRunnable);
thread2.setName("线程2");
thread1.start();
thread2.start();
}
}
三个窗口卖票2
/**
* 跟卖票1不一样的是,这里的ticket票数没有使用static,
* 因为上面是new了3个对象,所以有3个ticket
* 但这里是只new了一个对象,给了3个线程用
**/
public class