学完java的多线程我们可以了解到我们的程序是如何进行的,之前我们所学过的知识都是单线程的
什么是程序、进程、线程(概念性的理解)
程序: 用某种语言编写的一组指令的集合,即是一种静态的代码,静态的对象、
进程: 是程序的一次执行过程,或是正在运行的一个程序,是一个动态的过程。
进程的缺点:内存的浪费,cpu负担
线程:进程可进一步细化为线程,是一个内部的一条执行路径。
若一个进程同一时间并执行多个线程,就是支持多线程的
创建线程的方式一:继承Thread来进行创建线程
/**
* @Auther:Yuhai
* @Date:2022/4/10-04-10-22:17
* @Description:IntelliJ IDEA
* @version:1.0
* 多线程的创建,方式1:继承Thread类
* 创建一个继承于Thread类的子类
* 重写Thread类的run()方法-->将此线程执行的操作声明在run()方法中
* 创建Thread类的子类的对象
* 通过此对象调用Start()
*
* 例子: 遍历100以内的所有偶数
*/
//创建一个继承于Thread类的子类
class MyThread extends Thread {
//重写Thread类的run()方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
/*
Thread.currentThread().getName(): 获取当前主线程的名字
*/
public class ThreadTest {
public static void main(String[] args) {
//创建Thread类的子类的对象
MyThread myThread = new MyThread();
//通过此对象调用Start(),1.启动当前主线程,2.调用当前线程的run()方法。
myThread.start();
//问题一:我们不能通过直接调用run()方法启动主线程
// myThread.run();
//问题二:在启动一个线程,遍历100以内的偶数,不可以还让已经start()的线程去执行,会报IllegalThreadStateException异常的
//IllegalThreadStateException非法的线程状态
//此时我们需要创建一个新的对象
//想要启动多个线程时,就需要创建多个对象
MyThread myThread1 = new MyThread();
myThread1.start();
//下面的操作,仍然在main线程中执行的
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
// System.out.println(i+"*********main()****************");
System.out.println(Thread.currentThread().getName() + ":" + i + "*********main()****************");
}
}
}
}
创建多线程的方式二:
实现Runnable接口来创建多线程
ublic class RunnableTest implements Runnable {
@Override
public void run() {
for (int i = 0; i <10 ; i++) {
System.out.println("第"+i+"此thread执行");
}
}
public static void main(String[] args) {
//main作为主线程,所以首先会执行他的
//创建对象
RunnableTest rd = new RunnableTest();
Thread t = new Thread(rd);
t.start();
for (int i = 0; i <5 ; i++) {
System.out.println("main----->"+i);
}
}
}
总结:继承Thraed类和实现Runnable接口的比较
实现Runnable接口的方式会比继承Thread类的方式好,理由如下
java是单继承的,应该把继承的位置留给重要的东西,而实现接口实现多线程还是比较常用的,可以避免单继承的风险,而且还可以方便共享同一个资源。
接下来我们上一个练习:
使用多线程方式来遍历100以内的偶数,要求使用以上两种方式
/*
方法1,继承Thread类来-->重写run方法--->创建对象调用start来进行操作
*/
public class ThreadWork1 {
public static void main(String[] args) {
//创建各自的对象,来使用,进行输出
Test t = new Test();
t.start();
}
}
class Test extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
}
/*
方法2:实现Runnable接口来进行操作
*/
public class ThreadWork1 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(i);
}
}
}
public static void main(String[] args) {
//创建对象,调用方法
ThreadWork1 threadWork1 = new ThreadWork1();
Thread thread = new Thread(threadWork1);
thread.start();
//也可以用对象直接调用run
//threadWork1.run();
}
}
线程的状态:
1.新建:当一个Thread类或子类的对象被声明并创建时,新生的线程对象处于新建状态
2.就绪:处于新建状态的线程被start()后,将进入的线程队列等待CPU时间片,此时他已经具备了运行条件,只是没有分配到CPU资源
3.运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run()方法定义了线程的操作和功能
4.阻塞:在某种特殊的情况下,被人挂起或执行输入输出的操作时,让出CPU并临时中止自己的执行,进入阻塞状态
5.死亡:线程完成他的全部工作或线程被提前强制性地中止或出现异常导致
线程的相关的API:
/**
* @Auther:Yuhai
* @Date:2022/4/11-04-11-13:01
* @Description:IntelliJ IDEA
* @version:1.0
*
*Thread常用方法的使用
*
* 1. start() :1.启动当前主线程 2。调用线程的run()方法
* 2. run() : 通常需要重写Thread类中的此方法,将创键的线程要操作执行的操作方法声明在此方法中
* 3. yield():主动释放当前主线程的执行权
* 4. join(): 在线程中插入执行另一个线程,该线程被阻塞,直接插入执行的线程完全执行完毕后,该线程才能继续执行下去
* 5. stop(): 过时的方法。当执行此方法时,强制结束当前线程
* 6. sleep(long millitime): 线程休眠 一段时间
* 7. isAlive() ;判断当前线程是否存活
* 8. 1.getName获取当前线程的名字 2 .serName设置当前线程的名字
*
* 线程的优先级
* 1.MAX_PRIORITY:10
* MIN_PRIORITY:1
* NORM_PRIORITY:5---->默认的优先级
* 2.如何获取和设置当前线程的优先级
*
* 说明:高优先级的线程要抢占低优先级的cpu执行权,但是只是从概率上讲,高优先级的线程高概率的情况下被执行
* ,并不意味着只有当高优先级的线程执行来以后,低优先级的线程才执行
*/
public class ThreadMethodTest implements Runnable {
@Override
public void run(){
//用于输出当前执行线程的信息
System.out.println("名字:"+Thread.currentThread().getName());
System.out.println("id:"+Thread.currentThread().getId());
System.out.println("优先级:"+Thread.currentThread().getPriority());
System.out.println("状态:"+Thread.currentThread().getState());
System.out.println("是否存活:"+Thread.currentThread().isAlive());
System.out.println("所属线程组:"+Thread.currentThread().getThreadGroup());
System.out.println("该线程组的活动线程数目:"+Thread.activeCount());
System.out.println("线程信息String:"+Thread.currentThread().toString());
System.out.println("是否持有锁:"+Thread.holdsLock(this));
synchronized (this){
System.out.println("是否持有锁:"+Thread.holdsLock(this));
}
}
public static void main(String[] args) {
ThreadMethodTest threadMethodTest = new ThreadMethodTest();
//这是创建线程时起的名字,方便我们获取信息
Thread thread = new Thread(threadMethodTest,"test");
thread.setName("线程一");
threadMethodTest.run();
try {
Thread.sleep(1000);//休眠一段时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
上机练习
/**
* @Auther:Yuhai
* @Date:2022/4/15-04-15-17:17
* @Description:IntelliJ IDEA
* @version:1.0
*/
/**
* 利用睡眠的时间差进行交替输出,此时的代码要在逻辑代码里面,方才能进行交替输出,否则会输出错误。
* 一个让其停止结束的
*/
public class Demo1 implements Runnable {
@Override
public void run() {
for (int i = 1; i <=10; i++) {
System.out.println(Thread.currentThread().getName() + "----------" + i);
try {
Thread.sleep(1050);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Demo1 d = new Demo1();
Thread t = new Thread(d, "A线程");
t.start();
for (int i = 10; i >= 1; i--) {
System.out.println(Thread.currentThread().getName() + "B线程" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
总结:利用休眠的时间差来进行操作,这样也可以进行分开的操作
接下来剩下的有线程的同步和通信,我们下一个博客再见!GoodBye.