Java多线程基础-第一节1:多线程概念和Java中创建线程的方式
Posted 我擦我擦
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java多线程基础-第一节1:多线程概念和Java中创建线程的方式相关的知识,希望对你有一定的参考价值。
文章目录
一:什么是线程和多线程
线程:关于进程和线程的概念这里就不再重复了,具体可见
要想进行下一步学习,你至少要清楚以下概念
-
明白计算机的基本工作流程(冯诺依曼,寄存器、指令等概念)
-
什么是进程,如何理解进程
-
并行和并发
-
进程PCB的概念
-
进程调度与通信的概念
-
什么是线程、为什么要引入线程
-
进程和线程的区别
-
线程调度
-
用户级线程和内核级线程
-
多线程的概念
-
…
二:Java多线程引入
- 注意:不管是C++、Python还是Java,在多线程这一部分总是不太容易讲解,所以这里我们通过一个简单的例子来帮助大家理解
在之前的学习中,我们的代码只是运行在一个执行流中,如何证明?你会发现在这种单执行流中,不可能存在两个循环语句同时运行
- 当你运行Java程序后,就会产生一个进程,此时
main
方法是该进程中唯一存在的一个线程,也即主线程,当有多个线程时mian
方法就是所有线程的入口方法 - 下面代码中
Thread.sleep()
用于将线程阻塞一定时间
public class Test
public static void main(String[] args) throws InterruptedException
while(true)
System.out.println("main线程运行中");
Thread.sleep(1000);
而在多线程中,由于线程之间是并发运行的,所以每个线程内部都可以独立的进行工作,所以对于整个进程或程序来说,它就可以同时运行多个循环语句
在Java中,会使用Thread
类管理线程,用户在使用时线程时,需要自己实现一个线程类然后继承该Thread
类,接着在内部重写run
方法,run
方法里面的逻辑,就是这个线程要执行的工作,如下
- 注意:这仅是一种常见的创建线程的方式,还有其它方法,稍后说明
class MyThread extends Thread
@Override
public void run()
while(true)
System.out.println("这是MyThread线程");
try
Thread.sleep(1000);
catch (InterruptedException e)
throw new RuntimeException(e);
创建线程时,直接实例化线程类即可,不过需要注意只有在调用start
方法时,该线程才算被真正创建出来。如下,我们在main
方法中实例化刚才的线程,然后在main
方法内也写上一个循环语句
package threading;
class MyThread extends Thread
@Override
public void run()
while(true)
System.out.println("这是MyThread线程");
try
Thread.sleep(1000);
catch (InterruptedException e)
throw new RuntimeException(e);
public class TestDemo
public static void main(String[] args) throws InterruptedException
MyThread myThread = new MyThread();
myThread.start();
while(true)
System.out.println("这是main线程");
Thread.sleep(1000);
运行程序,你会发现两个循环在“交替”运行,这说明现在两个线程正在并发执行
多线程编程相较于普通编程难度会大大提高,稍有不慎就可能会导致整个系统崩溃。类似于任务管理器,为了方便我们对线程信息的掌控,Java提供了jconsole
命令来观察线程
找到jdk安装目录,在bin文件下找到jconsole.exe
,启动上面的程序后,双击jconsole.exe
在打开的窗口中选中对应的程序,然后点击连接
选择不安全的连接
进入监视窗口,选择线程
如下为线程运行信息,其中main
和Thread-0
就是上面例子所展示的那两个线程。可以发现还有很多其他线程,它们各司其职,有负责垃圾回收的,有负责监视的,也有负责跟踪的等等
三:Java线程生命周期
Java线程生命周期:在Java中,一个线程会历经如下状态,分别有与之对应的操作或条件
- 新建状态:使用关键字
new
和Thread
类或其子类建立一个线程对象后,该线程就处于新建状态。它会保持这个状态直到程序start()
这个线程 - 就绪状态:当线程对象调用了
start()
方法后,该线程进入就绪状态。就绪状态的线程处于就绪队列中,等待JVM调度 - 运行状态:如果就绪状态线程获取CPU资源,就可以执行
run()
,此线程便处于运行状态。处于运行状态的线程可以重新变为阻塞、就绪或死亡状态 - 阻塞状态:如果一个线程执行了
sleep
(睡眠)、suspend
(挂起)的等方法,失去所占用的资源后,就会进入阻塞状态。在睡眠时间已到或重新获得资源后可再次进入就绪状态。分为等待阻塞、同步阻塞或其他阻塞 - 死亡状态:个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态
四:创建线程的方法
(1)通过继承Thread类
通过继承Thread类:格式如下,这种方法使线程和线程需要完成的任务绑定在了一起,直接使用this
就表示当前线程对象的引用。所以这种写法耦合性太强,未来改动时代价较大
1:继承Thread类创建一个线程类
class MyThread extends Thread
@override
public void run()
System.out.println("线程运行逻辑")
2:创建MyThread类实例
MyThread thread0 = new MyThread();
3:调用start方法启动线程
thread0.strat();
(2)通过实现Runnable接口
通过实现Runnable接口:格式如下,这种方法把线程和线程需要完成的任务分开了,使用Runnable
专门表示线程需要完成的任务,此时this
表示的是Runnbale
对象的引用,如果要引用线程时则要借助Thread.currentThread()
。所以这种写法耦合性较低,未来改动时代价较低
1:实现Runnable接口
class MyRunnable implements Runnable
@Override
public void run()
System.out.println("线程运行逻辑");
2:创建Thread类实例,在调用Thread构造方法时将Runnable对象作为target参数
Thread thread0 = new Thread(new MyRunnable());
3:调用start方法
thread0.start();
例子:
package threading;
class MyRunnable implements Runnable
@Override
public void run()
while(true)
System.out.println("这是MyRunnable线程");
try
Thread.sleep(1000);
catch (InterruptedException e)
throw new RuntimeException(e);
public class TestDemo2
public static void main(String[] args) throws InterruptedException
Thread thread0 = new Thread(new MyRunnable());
thread0.start();
while(true)
System.out.println("这是main线程");
Thread.sleep(1000);
(3)变种形式
①:使用匿名内部类创建Thread子类对象
package threading;
public class TestDemo3
public static void main(String[] args) throws InterruptedException
Thread thread = new Thread()
@Override
//匿名内部类
public void run()
while(true)
System.out.println("这是MyThread线程");
try
Thread.sleep(1000);
catch (InterruptedException e)
throw new RuntimeException(e);
;
thread.start();
while(true)
System.out.println("这是main线程");
Thread.sleep(1000);
②:使用匿名内部类实现Runnable接口
package threading;
public class TestDemo4
public static void main(String[] args) throws InterruptedException
Thread thread = new Thread(
//匿名内部类
new Runnable()
@Override
public void run()
while(true)
System.out.println("这是MyRunnable线程");
try
Thread.sleep(1000);
catch (InterruptedException e)
throw new RuntimeException(e);
);
thread.start();
while(true)
System.out.println("这是main线程");
Thread.sleep(1000);
③:使用lambda表达式
package threading;
public class TestDemo5
public static void main(String[] args) throws InterruptedException
Thread thread0 = new Thread(
() ->
while(true)
System.out.println("lambda表达式Thread");
try
Thread.sleep(1000);
catch (InterruptedException e)
throw new RuntimeException(e);
);
thread0.start();
while(true)
System.out.println("这是main线程");
Thread.sleep(1000);
五:多线程的优势
多线程的最大优势还是在于提高计算速度,如下分别使用串行和并发的方式完成同样的运算
package threading;
public class threadAdvantaged
//数字300亿
public static final long COUNT = 200_0000_0000L;
public static void main(String[] args)
serial_execution();
concurrency_execution();
//串行执行
public static void serial_execution()
long begin = System.currentTimeMillis();
long a = 0;
for (long i = 0; i < COUNT; i++)
a++;
a = 0;
for (long i = 0; i < COUNT; i++)
a++;
long end = System.currentTimeMillis();
System.out.println("串行执行用时:" + (end - begin) + "ms");
//并发执行
public static void concurrency_execution()
long begin = System.currentTimeMillis();
Thread thread1 = new Thread(
new Runnable()
@Override
public void run()
long a = 0;
for (long i = 0; i < COUNT; i++)
a++;
);
Thread thread2 = new Thread(
new Runnable()
@Override
public void run()
long a = 0;
for (long i = 0; i < COUNT; i++)
a++;
);
thread1.start();
thread2.start();
//阻塞
try
thread1.join();
thread2.join();
catch (InterruptedException e)
e.printStackTrace();
long end = System.currentTimeMillis();
System.out.println("并发执行用时:" + (end - begin) + "ms");
以上是关于Java多线程基础-第一节1:多线程概念和Java中创建线程的方式的主要内容,如果未能解决你的问题,请参考以下文章
Java多线程基础-第一节4:synchronized关键字(监视器锁monitor lock)和volatile关键字