学完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() *
<p> * 例子: 遍历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(); } } }
上机练习
需求说明 – 定义一个线程 A ,输出 1 ~ 10 之间的整数,定义一个线程 B ,逆 序输出 1 ~ 10 之间的整数,要求线程 A 和线程 B 交替输出
• 分析 – 使用 sleep() 方法阻塞当前线程 /** * @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.