Java线程创建的四种方式总结
多线程的创建,方式一:继承于Thread类
1.创建一个继承于Thread类的子类
2.重写Thread类的run()--->将此线程执行的操作声明在run()中
3.创建Thread类的子类的对象
4.通过此对象调用start():
start()方法的两个作用:
A.启动当前线程
B.调用当前线程的run()
创建过程中的两个问题:
问题一:我们不能通过直接调用run()的方式启动线程
问题二:在启动一个线程,遍历偶数,不可以让已经start()的线程去执行,会报异常;正确的方式是重新创建一个线程的对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
//1.创建一个继承于Thread类的子类
class
MyThread
extends
Thread{
//2.重写Thread类的run()
@Override
public
void
run() {
//第二个线程
for
(
int
i =
0
;i <
10
;i++){
if
(i %
2
==
0
){
System.out.println(i);
}
}
}
}
public
class
ThreadTest {
public
static
void
main(String[] args) {
//主线程
//3.创建Thread类的子类的对象
MyThread t1 =
new
MyThread();
//4.通过此对象调用start()
t1.start();
//问题一:不能通过直接调用run()的方式启动线程
// t1.run();//错误的
//问题二:再启动一个线程:我们需要再创建 一个对象
//t1.start();//错误的
MyThread t2 =
new
MyThread();
t2.start();
for
(
int
i =
0
;i <
10
;i++){
if
(i %
2
!=
0
){
System.out.println(i +
"****main()******"
);
}
}
}
}
|
此代码在主线程内输出奇数,在另一个线程里输出偶数,则输出结果应该是两个输出结果是交互的。
1****main()******
3****main()******
5****main()******
7****main()******
0
2
4
6
8
9****main()******
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
class
Window
extends
Thread{
//创建三个窗口卖票, 总票数为100张,使用继承于Thread类的方式
private
static
int
ticket =
100
;
//三个窗口共享:声明为static
@Override
public
void
run() {
while
(
true
){
if
(ticket >
0
){
System.out.println(getName() +
":卖票,票号为:"
+ ticket);
ticket--;
}
else
{
break
;
}
}
}
}
public
class
WindowTest2 {
public
static
void
main(String[] args) {
Window t1 =
new
Window();
Window t2 =
new
Window();
Window t3 =
new
Window();
t1.setName(
"窗口1"
);
t2.setName(
"窗口2"
);
t3.setName(
"窗口3"
);
t1.start();
t2.start();
t3.start();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
public
class
ThreadDemo {
public
static
void
main(String[] args) {
// MyThread1 m1 = new MyThread1();
// MyThread2 m2 = new MyThread2();
// m1.start();
// m2.start();
//由于造的类只创建过一次对象,后面就不用了,可以考虑使用匿名类的方式
//创建Thread类的匿名子类的方式
new
Thread(){
@Override
public
void
run() {
for
(
int
i =
0
;i <
100
;i++){
if
(i %
2
==
0
){
System.out.println(i);
}
}
}
}.start();
new
Thread(){
@Override
public
void
run() {
for
(
int
i =
0
;i <
100
;i++){
if
(i %
2
!=
0
){
System.out.println(i);
}
}
}
}.start();
}
}
class
MyThread1
extends
Thread{
@Override
public
void
run() {
for
(
int
i =
0
;i <
100
;i++){
if
(i %
2
==
0
){
System.out.println(i);
}
}
}
}
class
MyThread2
extends
Thread{
@Override
public
void
run() {
for
(
int
i =
0
;i <
100
;i++){
if
(i %
2
!=
0
){
System.out.println(i);
}
}
}
}
|
创建多线程的方式二:实现Runnable接口
- 创建一个实现了Runnable接口的类
- 实现类去实现Runnable中的抽象方法:run()
- 创建实现类的对象
- 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
- 通过Thread类的对象调用start()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
class
MThread
implements
Runnable{
//2.实现类去实现Runnable中的抽象方法:run()
@Override
public
void
run() {
for
(
int
i =
0
;i <
100
;i++){
if
(i %
2
==
0
) {
System.out.println(Thread.currentThread().getName() +
":"
+ i);
}
}
}
}
public
class
ThreadTest1 {
public
static
void
main(String[] args) {
//3.创建实现类的对象
MThread mThread =
new
MThread();
//4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
Thread t1 =
new
Thread(mThread);
t1.setName(
"线程1"
);
//5.通过Thread类的对象调用start():A.启动线程B.调用当前线程的run()-->调用了Runnable类型的target
t1.start();
//再启动一个线程,遍历100以内的偶数//只需重新实现步骤4,5即可
Thread t2 =
new
Thread(mThread);
t2.setName(
"线程2"
);
t2.start();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
class
window1
implements
Runnable{
//创建三个窗口卖票, 总票数为100张,使用实现Runnable接口的方式
private
int
ticket =
100
;
Object obj =
new
Object();
@Override
public
void
run() {
while
(
true
){
if
(ticket >
0
) {
System.out.println(Thread.currentThread().getName() +
"卖票,票号为:"
+ ticket);
ticket--;
}
else
{
break
;
}
}
}
}
public
class
WindowTest {
public
static
void
main(String[] args) {
window1 w =
new
window1();
//只造了一个对象,所以100张票共享
Thread t1 =
new
Thread(w);
Thread t2 =
new
Thread(w);
Thread t3 =
new
Thread(w);
t1.setName(
"线程1"
);
t2.setName(
"线程2"
);
t3.setName(
"线程3"
);
t1.start();
t2.start();
t3.start();
}
}
|
创建线程的方式三:实现Callable接口---JDK5.0新增
与使用Runnable相比,Callable功能更强大些
>相比run()方法,可以有返回值
>方法可以抛出异常
>支持泛型的返回值
>需要借助FutureTask类,比如获取返回结果
Future接口
>可以对具体Runnable、Callable任务的执行结果进行取消、查询是否完成、获取结果等。
>FutureTask是Futrue接口的唯一的实现类
>FutureTaskb同时实现了Runnable,Future接口。它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
//1.创建一个实现Callable的实现类
class
NumThread
implements
Callable{
//2.实现call方法,将此线程需要执行的操作声明在call()中
@Override
public
Object call()
throws
Exception {
int
sum =
0
;
for
(
int
i =
1
;i <=
100
;i++){
if
(i %
2
==
0
){
System.out.println(i);
sum += i;
}
}
return
sum;
//sum是int,自动装箱为Integer(Object的子类)
}
}
public
class
ThreadNew {
public
static
void
main(String[] args) {
//3.创建Callable接口实现类的对象
NumThread numThread =
new
NumThread();
//4.将此Callable接口实现类的对象作为参数传递到 FutureTask的构造器中,创建FutureTask的对象
FutureTask futureTask =
new
FutureTask(numThread);
//5.将 FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
new
Thread(futureTask).start();
try
{
//获取Callable中call()的返回值(不是必须的步骤)
//get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。
Object sum = futureTask.get();
System.out.println(
"总和为:"
+ sum);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
catch
(ExecutionException e) {
e.printStackTrace();
}
}
}
|
创建线程的方式四:使用线程池--->JDK5.0新增
背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。
思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。
好处:>提高响应速度(减少了创建新线程的时间)
>降低资源消耗(重复利用线程池中线程,不需要每次都创建)
>便于线程管理:A.corePoolSize:核心池的大小 B.maximumPoolSize:最大线程数 C.keepAliveTime:线程没有任务时最多保持多长时间后会终止
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
class
NumberThread
implements
Runnable{
@Override
public
void
run() {
for
(
int
i =
0
;i <=
100
;i++){
if
(i %
2
==
0
){
System.out.println(Thread.currentThread().getName() +
":"
+ i);
}
}
}
}
class
NumberThread1
implements
Runnable{
@Override
public
void
run() {
for
(
int
i =
0
;i <=
100
;i++){
if
(i %
2
!=
0
){
System.out.println(Thread.currentThread().getName() +
":"
+ i);
}
}
}
}
public
class
ThreadPool {
public
static
void
main(String[] args) {
//1.提供指定线程数量的线程池
ExecutorService service = Executors.newFixedThreadPool(
10
);
ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
//设置线程池的属性
// System.out.println(service.getClass());
// service1.setCorePoolSize(15);
// service1.setKeepAliveTime();
//2.执行指定的线程操作。需要提供实现Runnable 接口或Callable接口实现类的对象
service.execute(
new
NumberThread());
//适用于Runnable
service.execute(
new
NumberThread1());
//适用于Runnable
// service.submit(Callable callable);//适用于Callable
//3.关闭连接池
service.shutdown();
}
}
|
比较创建线程的两种方式:
开发中:优先选择:实现Runnable接口的方式
原因:1.实现的方式没有类的单继承性的局限性
2.实现的方式更适合来处理多个线程有共享数据的情况。
系:public class Thread implements Runnable
相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中
程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
进程(process)是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程。---生命周期
线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路径。
线程作为调度和执行的单位,每个线程拥有独立的运行栈和计数器,每个进程拥有独立的方法区和堆;意味着,多个线程共享一个方法区和堆。而共享的就可以优化,同时,共享的也会带来安全隐患,这就需要我们解决线程安全问题
背景:以单核CPU为例,只使用单个线程先后完成多个任务(调用多个方法),肯定比用多个线程来完成用的时间更短,为何仍需使用多线程呢?
使用多线程的优点:
1.提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
2.提高计算机系统CPU的利用率
3.改善程序结构。将即长又复杂的线程分为多个线程,独立运行,利于理解和修改
何时需要多线程
1.程序需要同时执行两个或多个任务。
2.程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等。
3.需要一些后台运行的程序时。
1
2
3
4
5
6
7
8
9
10
11
12
|
public
class
Sample{
public
void
method1(String str){
System.out.println(str);
}
public
void
method2(String str){
method1(str);
}
public
static
void
main(String[] args){
Sample s =
new
Sample();
s.method2(
"hello!"
);
}
}
|
注意:此程序不是多线程!main方法中调用了method1,method1中又调用了method2;是一条执行路径,所以是单线程
测试Thread类的常用方法:
1.start():启动当前线程:调用当前线程的run()
2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
3.currentThread():静态方法,返回执行当前代码的线程
4.getName():获取当前线程的名字
5.setName():设置当前线程的名字
6.yield():释放当前CPU的执行权(下一刻CPU执行的线程仍是随机的)
>暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程
>若队列中没有同优先级的线程,忽略此方法
7.join():在线程a中调用线程b的join(),此时,线程a就进入阻塞状态(停止执行),直到线程b完全执行完以后,线程b才结束阻塞状态(开始执行)。
8.sleep(long millitime):让当前线程"睡眠"指定的millitime毫秒。在指定的millitime毫秒时间内,当前线程是阻塞状态。会抛出InterruptedException异常
* 9.isAlive():判断当前线程是否存活
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
class
HelloThread
extends
Thread{
@Override
public
void
run() {
for
(
int
i =
0
;i <
100
;i++){
if
(i %
2
!=
0
){
try
{
sleep(
1000
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
":"
+Thread.currentThread().getPriority() +
":"
+ i);
}
}
}
public
HelloThread(String name){
super
(name);
}
}
public
class
ThreadMethodTest {
public
static
void
main(String[] args) {
HelloThread h1 =
new
HelloThread(
"Thread:1"
);
//通过构造器给线程命名,但前期是得在子类中提供一个构造器
// h1.setName("线程一");
//设置分线程的优先级
h1.setPriority(Thread.MAX_PRIORITY);
h1.start();
//给主线程命名
Thread.currentThread().setName(
"主线程"
);
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
for
(
int
i =
0
;i <
100
;i++){
if
(i %
2
==
0
) {
System.out.println(Thread.currentThread().getName() +
":"
+ Thread.currentThread().getPriority() +
":"
+ i);
}
// if(i == 20){
// try {
// h1.join();//join()的测试
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
}
}
}
|
线程的优先级:
1.MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5--->默认优先级
2.如何获取和设置当前线程的优先级:
getPriority():获取线程的优先级
setPriority(int p):设置线程的优先级
说明:高优先级的线程要抢占低优先级线程CPU的执行权,但是只是从概率上讲,高优先级的线程高概率的情况下,不一定被执行,并不意味着只有当高优先级的线程执行完毕后,低优先级的线程才执行。
到此这篇关于Java线程创建的四种方式总结的文章就介绍到这了,更多相关Java 线程创建内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
<div class="art_xg">
<b>您可能感兴趣的文章:</b><ul><li><a href="/article/222390.htm" title="java中线程池最实用的创建与关闭指南" target="_blank">java中线程池最实用的创建与关闭指南</a></li><li><a href="/article/222000.htm" title="如何在Java中创建线程通信的四种方式你知道吗" target="_blank">如何在Java中创建线程通信的四种方式你知道吗</a></li><li><a href="/article/221810.htm" title="Java基础之多线程方法状态和创建方法" target="_blank">Java基础之多线程方法状态和创建方法</a></li><li><a href="/article/220601.htm" title="Java创建多线程的8种方式集合" target="_blank">Java创建多线程的8种方式集合</a></li><li><a href="/article/220593.htm" title="Java创建线程及配合使用Lambda方式" target="_blank">Java创建线程及配合使用Lambda方式</a></li><li><a href="/article/219117.htm" title="java实现/创建线程的几种方式小结" target="_blank">java实现/创建线程的几种方式小结</a></li><li><a href="/article/218451.htm" title="很多人竟然不知道Java线程池的创建方式有7种" target="_blank">很多人竟然不知道Java线程池的创建方式有7种</a></li><li><a href="/article/230524.htm" title="Java线程的三种创建方式" target="_blank">Java线程的三种创建方式</a></li></ul>
</div>
</div>
<!--endmain-->
<div class="lbd_bot clearfix"><script async="" src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script><ins class="adsbygoogle" style="display: block; height: 280px;" data-ad-client="ca-pub-6384567588307613" data-ad-slot="6445926239" data-ad-format="auto" data-full-width-responsive="true" data-adsbygoogle-status="done"><ins id="aswift_2_expand" style="border: none; height: 280px; width: 820px; margin: 0px; padding: 0px; position: relative; visibility: visible; background-color: transparent; display: inline-table;"><ins id="aswift_2_anchor" style="border: none; height: 280px; width: 820px; margin: 0px; padding: 0px; position: relative; visibility: visible; background-color: transparent; display: block;"></ins></ins></ins><script>(adsbygoogle = window.adsbygoogle || []).push({});</script></div><div id="ewm"><div class="jb51ewm"><div class="fl"><img src="//files.jb51.net/skin/2018/images/jb51ewm.png"></div><div class="fr"><p>微信公众号搜索 “ <span>脚本之家</span> ” ,选择关注</p><p>程序猿的那些事、送书等活动等着你</p></div></div></div><p>原文链接:https://blog.csdn.net/weixin_49329785/article/details/119323345</p>
<div class="tags clearfix">
<i class="icon-tag"></i>
<ul class="meta-tags">
<li class="tag item"><a href="http://common.jb51.net/tag/Java/1.htm" target="_blank" title="搜索关于Java的文章" rel="nofollow">Java</a></li>
- 创建
- 线程
</ul> </div> <div class="lbd clearfix"> <span id="art_down" class="jbTestPos"><div class="_ehxakvsihim"><iframe id="iframeu4846790_0" name="iframeu4846790_0" src="https://pos.baidu.com/jccm?conwid=820&conhei=250&rdid=4846790&dc=3&di=u4846790&s1=1957551844&s2=286292967&tr=1640163534&mt=ca9808a5f701784c&dri=0&dis=0&dai=2&ps=12703x105&enu=encoding&exps=110261,110252,110011&ant=0&aa=1&psi=a63fc0c71d859b27&dcb=___adblockplus_&dtm=HTML_POST&dvi=0.0&dci=-1&dpt=none&tpr=1640163534977&ti=Java%E7%BA%BF%E7%A8%8B%E5%88%9B%E5%BB%BA%E7%9A%84%E5%9B%9B%E7%A7%8D%E6%96%B9%E5%BC%8F%E6%80%BB%E7%BB%93_java_%E8%84%9A%E6%9C%AC%E4%B9%8B%E5%AE%B6&ari=2&ver=1221&dbv=2&drs=3&pcs=1381x685&pss=1381x14217&cfv=0&cpl=5&chi=1&cce=true&cec=UTF-8&tlm=1640163534&prot=2&rw=685&ltu=https%3A%2F%2Fwww.jb51.net%2Farticle%2F222819.htm&ltr=https%3A%2F%2Fwww.jb51.net%2Farticle%2F218451.htm&lcr=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3D-vZTSbp6puE19Zf32yQzKaIwzOVvSzp6Ua6KJDjTE7YjS44rzbc34GKOheA1BsmliuDjuE8B_q5fzT0nAdMWka%26wd%3D%26eqid%3Daee05f43000024310000000461c2b95a&ecd=1&uc=1536x824&pis=-1x-1&sr=1536x864&tcn=1640163535&qn=d049a1accc1414f2" width="820" height="250" scrolling="no" frameborder="0"></iframe></div></span> </div> <div id="shoucang"></div> <div class="xgcomm clearfix"> <h2>相关文章</h2> <ul><li class="lbd clearfix"><span id="art_xg" class="jbTestPos"><div class="_l1b8nyfd9ha"><iframe id="iframeu4806172_0" name="iframeu4806172_0" src="https://pos.baidu.com/jccm?conwid=820&conhei=120&rdid=4806172&dc=3&di=u4806172&s1=1498175115&s2=1110144838&tr=1640163534&mt=bcd882a6b7ee718d&dri=0&dis=0&dai=3&ps=13009x105&enu=encoding&exps=110261,110252,110011&ant=0&aa=1&psi=a63fc0c71d859b27&dcb=___adblockplus_&dtm=HTML_POST&dvi=0.0&dci=-1&dpt=none&tpr=1640163534977&ti=Java%E7%BA%BF%E7%A8%8B%E5%88%9B%E5%BB%BA%E7%9A%84%E5%9B%9B%E7%A7%8D%E6%96%B9%E5%BC%8F%E6%80%BB%E7%BB%93_java_%E8%84%9A%E6%9C%AC%E4%B9%8B%E5%AE%B6&ari=2&ver=1221&dbv=2&drs=3&pcs=1381x685&pss=1381x14466&cfv=0&cpl=5&chi=1&cce=true&cec=UTF-8&tlm=1640163534&prot=2&rw=685&ltu=https%3A%2F%2Fwww.jb51.net%2Farticle%2F222819.htm&ltr=https%3A%2F%2Fwww.jb51.net%2Farticle%2F218451.htm&lcr=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3D-vZTSbp6puE19Zf32yQzKaIwzOVvSzp6Ua6KJDjTE7YjS44rzbc34GKOheA1BsmliuDjuE8B_q5fzT0nAdMWka%26wd%3D%26eqid%3Daee05f43000024310000000461c2b95a&ecd=1&uc=1536x824&pis=-1x-1&sr=1536x864&tcn=1640163535&qn=9e268dcdbd17fc23" width="820" height="120" scrolling="no" frameborder="0"></iframe></div></span></li><li><div class="item-inner"><a href="/article/208300.htm" title="IDEA插件FindBugs的使用详解" class="img-wrap" target="_blank"> <img alt="IDEA插件FindBugs的使用详解" src="//img.jbzj.com/images/xgimg/bcimg0.png"> </a><div class="rbox"><div class="rbox-inner"><p><a class="link title" target="_blank" href="/article/208300.htm" title="IDEA插件FindBugs的使用详解">IDEA插件FindBugs的使用详解</a></p><div class="item-info"><div class="js">这篇文章主要介绍了IDEA插件FindBugs的使用详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下</div><span class="lbtn" style="float:right"> 2021-03-03 </span></div></div></div></div></li>
-
Springboot基于maven打包分离lib及resource
这篇文章主要介绍了Springboot基于maven打包分离lib及resource,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下2020-10-10 -
struts2中simple主题下<s:fieldError>标签默认样式的移除方法
这篇文章主要给大家介绍了关于struts2中simple主题下<s:fieldError>标签默认样式的移除方法,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧2018-10-10
最新评论