JAVA中多线程实现
2017-09-09 09:37
211 查看
在Java中实现我线程,有两种方式:继承Tread类;实现Runnable接口(或接口Callable,Jdk1.5之后)。
1 继承Tread类
Tread类是一个支持多线程的功能类,只要有一个子类继承它,就可以实现多线程的支持。我们都知道所有程序的起点是main()方法,但是所有的线程也一定要有一个自己的起点,那就是run()方法,所以我们必须覆写Thread类中的run()方法。这个方法没有返回值,那么就表示线程一旦开始就要一直执行,不能返回内容。
创建一个线程类来循环输出
实现测试类:
我们可以看到调用run()方法无法实现多线程,只有调用start()才可以,而且这也是唯一运行多线程的方法,那为什么它可以呢,我们必须要通过分析源码才能知道一二。
start()方法源码:
在上面这段源代码(我修改过注释),我们看到private native void start0()这个不熟悉的定义,我们可以看到此方法的的结构与抽象方法类似,使用了nativa声明。这里使用了Java开发中的JNI(Java Native Interface)技术,它特点是使用Java调用本机操作系统提供的函数,但是这样的技术有一个缺点,不能离开特定的操作系统。那样我只要在不同的系统上提供不同的JVM来实现这个方法,然后调用该系统的特定的函数来完成我们需要的功能。比如说这里:JVM在某个系统中实现start0()这个
方法,去调用系统中某个方法来申请资源与创建线程等。
即:调用start()方法不仅仅要启动多线程的执行代码,还要去根据不同的操作系统来进行资源的分配。
2 实现Runnable接口
虽然Tread类可以实现多线程的文体定义,但是它有一个问题,java具有单继承的实现,所以我们针对类继承都应该是回避的问题。
用Runnable来实现上面的类
我们可以发现上面的代码几乎不用修改就可以得到我们想要的类。但是我们需要对测试类要进行修改,因为Runnable是一个函数式接口,只有一个run()方法没有start()方法。同时必须要强调一下,不管何种情况下,如果想启动多线程一定是依靠Tread类的start()方法完成。但是Tread与Runnable没有什么联系,但是在Tread类中定义有 public Thread(Runnable target)这样的一个方法。所以我们可以通过以下的方式来实现多线程。
此时就避免了单继承的局限,那么也就是说在以后要实现多线程都应该使用Runnable实现。
3 多线程两种实现方式的区别
A 使用Runnable接口与Thread,解决了单继承的定义的局限 ;
B 我们能过查看Thread或者文档都可以看到Thread的定义如下:public class Thread implements Runnable,Thread实现了Runnable接口,而且我们的MyThread也实现了Runnable接口,同时MyThread对象是由Thread类对象操作的。MyThread类主要是实现多线程的核心功能,需Thread实现的是操作系统资源的分配与调用核心功能,这与我们的代理设计模式很相似(Thread是代理类,Mythread是真实操作主题),但是客户端调用的方法不是接口中的run()方法;
C 使用Runnable接口可以比Thread类更能够表现出数据共享(多个线程访问同资源的操作);
Thread子类实现卖花;
测试类
运行结果
通过运行结果我们可以看出,它们并没有实现数据共享,而是各自卖自己的花。
Runnable实现卖花;
测试类
运行结果
通过运行结果我们可以看出,它们实现数据共享,共同卖10朵花。当然Thread子类也可以,但是相对而言并没有那么容易。
4 Callable实现多线程
使用Runnable接口实现多线程可以避免单继承局限,但是有一个问题,Runnable接口里面的run()方法做为线程的主方法,不能返回操作结果。有人认识里可以返回一个结果,所以提供了Callable接口(函数式接口)。它是在java.util.concurrent这个工具包下。定义如下:public interface Callable<V>。
实现卖花:
但是Thread并没有一个构造方法可以接收Callable对象,但是在java.util.concurrent中有一个类,这个类主要是负责Callable接口对象 的操作的,这个接口的定义结构如下public class FutureTask<V> implements RunnableFuture<V>,我们再打 RunnableFuture,可以看到它的定义如下public interface RunnableFuture<V>
extends Runnable, Future<V>,现在是不是觉得很幸福,终于找到自己想要的Runnable接口,现在我们再看回 RunnableFuture这个类,当中有一个构造方法如下: public FutureTask(Callable<V> callable),类之间关系有点复杂,不过多看看源码,就不会觉得这有什么了,找不到,那么往上找,拄相关的类名找,最终还是能找到的。
测试类的实现:
运行结果:
这种设计方式是比麻烦,没有特殊要求不建议使用。
1 继承Tread类
Tread类是一个支持多线程的功能类,只要有一个子类继承它,就可以实现多线程的支持。我们都知道所有程序的起点是main()方法,但是所有的线程也一定要有一个自己的起点,那就是run()方法,所以我们必须覆写Thread类中的run()方法。这个方法没有返回值,那么就表示线程一旦开始就要一直执行,不能返回内容。
创建一个线程类来循环输出
package com.test; public class MyThread extends Thread{ private String name ; //定义属性 public MyThread(String name) { this.name = name ; } @Override public void run() { //覆写run方法,作为线程的主体操作方法 for(int x = 0 ; x < 100 ; ++ x){ System.out.println(this.name + " " + x); } } }
实现测试类:
package com.test; public class Test { public static void main(String[] args) { //创建线程 MyThread mt1 = new MyThread("线程A"); MyThread mt2 = new MyThread("线程B"); MyThread mt3 = new MyThread("线程C"); //运行线程 //调用run来运行,发现并不是多线程,而是顺序运行,这只是仅仅运行了方法体 //线程的创建是由系统来创建的,当中需要进行资源的分配 //mt1.run(); //mt2.run(); //mt3.run(); //应该调用start()方法,执行的功能是run()定义的 mt1.start(); mt2.start(); mt3.start(); } }
我们可以看到调用run()方法无法实现多线程,只有调用start()才可以,而且这也是唯一运行多线程的方法,那为什么它可以呢,我们必须要通过分析源码才能知道一二。
start()方法源码:
//synchronized表示这个方法是线程安全的 public synchronized void start() { if (threadStatus != 0)//表示每个线程只能启动一次 throw new IllegalThreadStateException(); /* Notify the group that this thread is about to be started * so that it can be added to the group's list of threads * and the group's unstarted count can be decremented. */ group.add(this); boolean started = false; try { //这个方法也正是能实现多线程的原因 start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { /* do nothing. If start0 threw a Throwable then it will be passed up the call stack */ } } } private native void start0();
在上面这段源代码(我修改过注释),我们看到private native void start0()这个不熟悉的定义,我们可以看到此方法的的结构与抽象方法类似,使用了nativa声明。这里使用了Java开发中的JNI(Java Native Interface)技术,它特点是使用Java调用本机操作系统提供的函数,但是这样的技术有一个缺点,不能离开特定的操作系统。那样我只要在不同的系统上提供不同的JVM来实现这个方法,然后调用该系统的特定的函数来完成我们需要的功能。比如说这里:JVM在某个系统中实现start0()这个
方法,去调用系统中某个方法来申请资源与创建线程等。
即:调用start()方法不仅仅要启动多线程的执行代码,还要去根据不同的操作系统来进行资源的分配。
2 实现Runnable接口
虽然Tread类可以实现多线程的文体定义,但是它有一个问题,java具有单继承的实现,所以我们针对类继承都应该是回避的问题。
用Runnable来实现上面的类
package com.test; public class MyThread implements Runnable{ private String name ; //定义属性 public MyThread(String name) { this.name = name ; } @Override public void run() { //覆写run方法,作为线程的主体操作方法 for(int x = 0 ; x < 100 ; ++ x){ System.out.println(this.name + " " + x); } } }
我们可以发现上面的代码几乎不用修改就可以得到我们想要的类。但是我们需要对测试类要进行修改,因为Runnable是一个函数式接口,只有一个run()方法没有start()方法。同时必须要强调一下,不管何种情况下,如果想启动多线程一定是依靠Tread类的start()方法完成。但是Tread与Runnable没有什么联系,但是在Tread类中定义有 public Thread(Runnable target)这样的一个方法。所以我们可以通过以下的方式来实现多线程。
package com.test; public class Test { public static void main(String[] args) { //创建线程 MyThread mt1 = new MyThread("线程A"); MyThread mt2 = new MyThread("线程B"); MyThread mt3 = new MyThread("线程C"); new Thread(mt1).start(); new Thread(mt2).start(); new Thread(mt3).start(); } }
此时就避免了单继承的局限,那么也就是说在以后要实现多线程都应该使用Runnable实现。
3 多线程两种实现方式的区别
A 使用Runnable接口与Thread,解决了单继承的定义的局限 ;
B 我们能过查看Thread或者文档都可以看到Thread的定义如下:public class Thread implements Runnable,Thread实现了Runnable接口,而且我们的MyThread也实现了Runnable接口,同时MyThread对象是由Thread类对象操作的。MyThread类主要是实现多线程的核心功能,需Thread实现的是操作系统资源的分配与调用核心功能,这与我们的代理设计模式很相似(Thread是代理类,Mythread是真实操作主题),但是客户端调用的方法不是接口中的run()方法;
C 使用Runnable接口可以比Thread类更能够表现出数据共享(多个线程访问同资源的操作);
Thread子类实现卖花;
package com.test; public class MyThread extends Thread{ private int num = 10 ; @Override public void run() { //覆写run方法,作为线程的主体操作方法 for(int x = 0 ; x < 100 ; ++ x){ if (this.num > 0) { System.out.println("卖花,还要卖"+ this.num -- + "枝花" ); } } } }
测试类
package com.test; public class Test { public static void main(String[] args) { MyThread mt1 = new MyThread(); MyThread mt2 = new MyThread(); MyThread mt3 = new MyThread(); mt1.start(); mt2.start(); mt3.start(); } }
运行结果
通过运行结果我们可以看出,它们并没有实现数据共享,而是各自卖自己的花。
Runnable实现卖花;
package com.test; public class MyThread implements Runnable{ private int num = 10 ; @Override public void run() { //覆写run方法,作为线程的主体操作方法 for(int x = 0 ; x < 100 ; ++ x){ if (this.num > 0) { System.out.println("卖花,还要"+ this.num -- + "枝花" ); } } } }
测试类
package com.test; public class Test { public static void main(String[] args) { MyThread mt = new MyThread(); new Thread(mt).start(); new Thread(mt).start(); new Thread(mt).start(); } }
运行结果
通过运行结果我们可以看出,它们实现数据共享,共同卖10朵花。当然Thread子类也可以,但是相对而言并没有那么容易。
4 Callable实现多线程
使用Runnable接口实现多线程可以避免单继承局限,但是有一个问题,Runnable接口里面的run()方法做为线程的主方法,不能返回操作结果。有人认识里可以返回一个结果,所以提供了Callable接口(函数式接口)。它是在java.util.concurrent这个工具包下。定义如下:public interface Callable<V>。
实现卖花:
package com.test; import java.util.concurrent.Callable; public class MyThread implements Callable< a673 ;string>{ private int num = 10 ; @Override public String call() throws Exception { for(int x = 0 ; x < 100 ; ++ x){ if (this.num > 0) { System.out.println("卖花,还要卖"+ this.num -- + "枝花" ); } } return "花已经卖光"; } } </string>
但是Thread并没有一个构造方法可以接收Callable对象,但是在java.util.concurrent中有一个类,这个类主要是负责Callable接口对象 的操作的,这个接口的定义结构如下public class FutureTask<V> implements RunnableFuture<V>,我们再打 RunnableFuture,可以看到它的定义如下public interface RunnableFuture<V>
extends Runnable, Future<V>,现在是不是觉得很幸福,终于找到自己想要的Runnable接口,现在我们再看回 RunnableFuture这个类,当中有一个构造方法如下: public FutureTask(Callable<V> callable),类之间关系有点复杂,不过多看看源码,就不会觉得这有什么了,找不到,那么往上找,拄相关的类名找,最终还是能找到的。
测试类的实现:
package com.test; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class Test { public static void main(String[] args) throws InterruptedException, ExecutionException { MyThread mt1 = new MyThread(); MyThread mt2 = new MyThread(); FutureTask<string> task1 = new FutureTask<>(mt1); FutureTask<string> task2 = new FutureTask<>(mt2); //FutureTask 是Runnable接口的子类,所以可以使用Thread类的构造来接收task对象 new Thread(task1).start(); new Thread(task2).start(); System.out.println("线程1的返回值:" + task1.get()); System.out.println("线程2的返回值:" + task1.get()); } } </string></string>
运行结果:
这种设计方式是比麻烦,没有特殊要求不建议使用。
相关文章推荐
- JAVA 中多线程服务端 多个客户端的实现
- 用JAVA的多线程实现火车站售票问题
- 用JAVA的多线程实现银行取款的问题
- Java多线程实现异步调用
- Java多线程编程环境中单例模式的实现
- JAVA 中多线程服务端 多个客户端的实现
- JAVA匿名实现多线程
- Java多线程编程环境中单例模式的实现
- Java中实现多线程
- java多线程学习二:两种实现多线程方式的对比
- java多线程的两种实现方式
- 在华为实现的java访问https,多线程,写日志
- 实现 Java 多线程并发控制框架
- Java 多线程 爬虫程序(spider)设计与实现
- Java多线程-一个简单的线程,实现挂起和恢复的功能
- 实现 Java 多线程并发控制框架
- 用java多线程实现一个控制台聊天室
- 彻底明白Java的多线程-实现多线程及线程的同步
- java 用多线程实现多生产者和多消费者模式
- 在Java中实现多线程