继承Thread类创建线程类
1
|
public class Thread extends Object implements Runnable |
- 定义Thread类的子类,并重写其run()方法
- 创建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
|
public class FirstThread extends Thread { public void run(){ for ( int i= 0 ;i< 100 ;i++){ /* * Thread类已经继承了Object * Object类创建了name选项 并且有其getName(),setName()方法 * 在继承Thread的类里面使用时只需要用this引用 */ System.out.println( this .getName()+ " " +i); } } public static void main(String[] args) { for ( int i= 0 ;i< 100 ;i++){ System.out.println(Thread.currentThread().getName()+ " " +i); if (i== 20 ){ new FirstThread().start(); new FirstThread().start(); } } } } |
Thread类已经继承了Object
Object类创建了name选项 并且有其getName(),setName()方法
在继承Thread的类里面使用时只需要用this引用
上面两个副线程和主线程随机切换,又因为使用的是继承Thread的类所以两个副线程不能共享资源
start()方法调用后并不是立即执行多线程代码,而是使得该线程编程可运行状态,什么时候运行是由操作系统决定的
实现Runnable接口创建线程类
1
2
3
|
public Thread() public Thread(Runnable target) public Thread(Runnable target,String name) |
- 定义Runnable接口的实现类,并重写该接口的run()方法
- 创建Runnable实现类的实例,并以此作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class SecondThread implements Runnable { public void run(){ for ( int i= 0 ;i< 100 ;i++){ System.out.println(Thread.currentThread().getName()+ " " +i); } } public static void main(String[] args) { for ( int i= 0 ;i< 100 ;i++){ System.out.println(Thread.currentThread().getName()+ " " +i); if (i== 20 ){ SecondThread st= new SecondThread(); //通过new Thread(target,name)创建线程 new Thread(st, "新线程1" ).start(); new Thread(st, "新线程2" ).start(); } } } } |
上面的结果是两个副线程和主线程随机切换,但是并没有共享资源,因为他们根本没有能用来共享的资源。
start()方法调用后并不是立即执行多线程代码,而是使得该线程编程可运行状态,什么时候运行是由操作系统决定的
继承Thread类和创建Runnable接口的共享资源详解
在只有可以用来共享的资源时候,也就是同用一个实例化对象。两个创建方式在共享资源时才会有所区别,否则它们都不会共享资源共享资源通常用private static 修饰符来修饰。
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
|
class Thread1 extends Thread{ private int count= 5 ; private String name; public Thread1(String name) { this .name=name; } public void run() { for ( int i = 0 ; i < 5 ; i++) { System.out.println(name + "运行 count= " + count--); try { sleep(( int ) Math.random() * 10 ); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Main { public static void main(String[] args) { Thread1 mTh1= new Thread1( "A" ); Thread1 mTh2= new Thread1( "B" ); mTh1.start(); mTh2.start(); } } |
1
2
3
4
5
6
7
8
9
10
|
B运行 count= 5 A运行 count= 5 B运行 count= 4 B运行 count= 3 B运行 count= 2 B运行 count= 1 A运行 count= 4 A运行 count= 3 A运行 count= 2 A运行 count= 1 |
正是因为有了private int count=5;一句才有了共享资源,但这是继承Thread类的子类,并不能共享资源
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 Thread2 implements Runnable{ private int count= 15 ; public void run() { for ( int i = 0 ; i < 5 ; i++) { System.out.println(Thread.currentThread().getName() + "运行 count= " + count--); try { Thread.sleep(( int ) Math.random() * 10 ); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Main { public static void main(String[] args) { Thread2 my = new Thread2(); new Thread(my, "C" ).start(); //同一个mt,但是在Thread中就不可以,如果用同一个实例化对象mt,就会出现异常 new Thread(my, "D" ).start(); new Thread(my, "E" ).start(); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
C运行 count= 15 D运行 count= 14 E运行 count= 13 D运行 count= 12 D运行 count= 10 D运行 count= 9 D运行 count= 8 C运行 count= 11 E运行 count= 12 C运行 count= 7 E运行 count= 6 C运行 count= 5 E运行 count= 4 C运行 count= 3 E运行 count= 2 |
同样的正是因为有了private int count=15这个共同的实例化对象,实现Runnable的类才可以共享资源
那么为什么继承Thread类的子类实现Runable接口的类在共享资源时有区别呢?
因为Java中只能支持单继承,单继承特点意味着只能有一个子类去继承 而Runnabl接口后可以跟好多类,便可以进行多个线程共享一个资源的操作
使用Callable和Future创建线程
Callable怎么看起来都像Runnable接口的增强版,Callable有一个call()方法相当于Runnable的run()方法,但是功能却更加强大:
call()方法可以有返回值
call()方法可以声明抛出异常
Callable接口有泛型限制,Callable接口里的泛型形参类型与call()方法的返回值类型相同。 而且Callable接口是函数式接口,因此可使用Lambda表达式创建Callable对象 Runnable接口也是函数式接口,因此也可以使用Lambda表达式创建Runnable对象
- 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,再创建Callable实现类的实例
- 使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法
- 使用FutureTask类对象作为Thread对象的target创建并启动新线程
- 调用FutureTask对象的get()方法来获得子线程结束后的返回值
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
|
public class ThirdThread implements Callable<Integer> { public Integer call(){ int i= 0 ; for (;i< 100 ;i++){ System.out.println(Thread.currentThread().getName()+ " " +i); } return i; } public static void main(String[] args){ ThirdThread tt= new ThirdThread(); FutureTask<Integer> task= new FutureTask<>(tt); Thread t= new Thread(task, "有返回值的线程" ); for ( int i= 0 ;i< 100 ;i++){ System.out.println(Thread.currentThread().getName()+ " " +i); if (i== 20 ){ t.start(); } } try { System.out.println( "返回值是:" +task.get()); } catch (Exception e){ e.printStackTrace(); } } } |
使用Lambda表达式的Callable和Future创建的线程
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
|
public class ThirdThread{ public static void main(String[] args){ ThirdThread tt= new ThirdThread(); //先使用Lambda表达式创建Callable<Integer>对象 //使用FutureTask封装Callable对象 FutureTask<Integer> task= new FutureTask<Integer>((Callable<Integer>)()->{ int i= 0 ; for (;i< 100 ;i++){ System.out.println(Thread.currentThread().getName()+ "的循环变量i的值:" +i); } return i; }); for ( int i= 0 ;i< 100 ;i++){ System.out.println(Thread.currentThread().getName()+ "的循环变量i的值:" +i); if (i== 20 ){ new Thread(task, "有返回值的线程" ).start(); } } try { System.out.println( "子线程的返回值" +task.get()); } catch (Exception e){ e.printStackTrace(); } } } |
如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
原文链接:http://blog.csdn.net/gailyyelp/article/details/77969652