#include<thread>
#include<future>
using namespace std;
class A
{
public:
void f(int x,char c){}
int operator()(int N) { return 0; }
};
void foo(int x){}
int main()
{
A a;
thread t1(a, 6); //传递a的拷贝给子线程
thread t2(ref(a), 6); //传递a的引用给子线程
thread t3(move(a), 6);//a在主线程中将不再有效
thread t4(A(), 6); //传递临时创建的a对象给子线程
thread t5(foo, 6); // 声明的函数:foo
thread t6([](int x) {return xx; }, 6); // lambda函数
thread t7(&A::f, a, 8, 'w'); //传递a的拷贝的成员函数给子线程 8和'w'是f()的参数
thread t8(&A::f, &a, 8, 'w'); //传递a的地址的成员函数给子线程
//async同样适用于以上八种方法
async(launch::async, a, 6);
return 0;
}
Java多线程的创建及启动
Java中线程的创建常见有如三种基本形式
1继承Thread类,重写该类的run()方法。
复制代码
1 class MyThread extends Thread {
2
3 private int i = 0;
4
5 @Override
6 public void run() {
7 for (i = 0; i < 100; i++) {
8 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
9 }
10 }
11 }
复制代码
复制代码
1 public class ThreadTest {
2
3 public static void main(String[] args) {
4 for (int i = 0; i < 100; i++) {
5 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
6 if (i == 30) {
7 Thread myThread1 = new MyThread(); // 创建一个新的线程 myThread1 此线程进入新建状态
8 Thread myThread2 = new MyThread(); // 创建一个新的线程 myThread2 此线程进入新建状态
9 myThread1start(); // 调用start()方法使得线程进入就绪状态
10 myThread2start(); // 调用start()方法使得线程进入就绪状态
11 }
12 }
13 }
14 }
复制代码
如上所示,继承Thread类,通过重写run()方法定义了一个新的线程类MyThread,其中run()方法的方法体代表了线程需要完成的任务,称之为线程执行体。当创建此线程类对象时一个新的线程得以创建,并进入到线程新建状态。通过调用线程对象引用的start()方法,使得该线程进入到就绪状态,此时此线程并不一定会马上得以执行,这取决于CPU调度时机。
2实现Runnable接口,并重写该接口的run()方法,该run()方法同样是线程执行体,创建Runnable实现类的实例,并以此实例作为Thread类的target来创建Thread对象,该Thread对象才是真正的线程对象。
复制代码
1 class MyRunnable implements Runnable {
2 private int i = 0;
3
4 @Override
5 public void run() {
6 for (i = 0; i < 100; i++) {
7 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
8 }
9 }
10 }
复制代码
复制代码
1 public class ThreadTest {
2
3 public static void main(String[] args) {
4 for (int i = 0; i < 100; i++) {
5 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
6 if (i == 30) {
7 Runnable myRunnable = new MyRunnable(); // 创建一个Runnable实现类的对象
8 Thread thread1 = new Thread(myRunnable); // 将myRunnable作为Thread target创建新的线程
9 Thread thread2 = new Thread(myRunnable);
10 thread1start(); // 调用start()方法使得线程进入就绪状态
11 thread2start();
12 }
13 }
14 }
15 }
复制代码
相信以上两种创建新线程的方式大家都很熟悉了,那么Thread和Runnable之间到底是什么关系呢?我们首先来看一下下面这个例子。
复制代码
1 public class ThreadTest {
2
3 public static void main(String[] args) {
4 for (int i = 0; i < 100; i++) {
5 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
6 if (i == 30) {
7 Runnable myRunnable = new MyRunnable();
8 Thread thread = new MyThread(myRunnable);
9 threadstart();
10 }
11 }
12 }
13 }
14
15 class MyRunnable implements Runnable {
16 private int i = 0;
17
18 @Override
19 public void run() {
20 Systemoutprintln("in MyRunnable run");
21 for (i = 0; i < 100; i++) {
22 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
23 }
24 }
25 }
26
27 class MyThread extends Thread {
28
29 private int i = 0;
30
31 public MyThread(Runnable runnable){
32 super(runnable);
33 }
34
35 @Override
36 public void run() {
37 Systemoutprintln("in MyThread run");
38 for (i = 0; i < 100; i++) {
39 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
40 }
41 }
42 }
复制代码
同样的,与实现Runnable接口创建线程方式相似,不同的地方在于
1 Thread thread = new MyThread(myRunnable);
那么这种方式可以顺利创建出一个新的线程么?答案是肯定的。至于此时的线程执行体到底是MyRunnable接口中的run()方法还是MyThread类中的run()方法呢?通过输出我们知道线程执行体是MyThread类中的run()方法。其实原因很简单,因为Thread类本身也是实现了Runnable接口,而run()方法最先是在Runnable接口中定义的方法。
1 public interface Runnable {
2
3 public abstract void run();
4
5 }
我们看一下Thread类中对Runnable接口中run()方法的实现:
复制代码
@Override
public void run() {
if (target != null) {
targetrun();
}
}
复制代码
也就是说,当执行到Thread类中的run()方法时,会首先判断target是否存在,存在则执行target中的run()方法,也就是实现了Runnable接口并重写了run()方法的类中的run()方法。但是上述给到的列子中,由于多态的存在,根本就没有执行到Thread类中的run()方法,而是直接先执行了运行时类型即MyThread类中的run()方法。
3使用Callable和Future接口创建线程。具体是创建Callable接口的实现类,并实现clall()方法。并使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象作为Thread对象的target来创建线程。
看着好像有点复杂,直接来看一个例子就清晰了。
复制代码
1 public class ThreadTest {
2
3 public static void main(String[] args) {
4
5 Callable<Integer> myCallable = new MyCallable(); // 创建MyCallable对象
6 FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask来包装MyCallable对象
7
8 for (int i = 0; i < 100; i++) {
9 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
10 if (i == 30) {
11 Thread thread = new Thread(ft); //FutureTask对象作为Thread对象的target创建新的线程
12 threadstart(); //线程进入到就绪状态
13 }
14 }
15
16 Systemoutprintln("主线程for循环执行完毕");
17
18 try {
19 int sum = ftget(); //取得新创建的新线程中的call()方法返回的结果
20 Systemoutprintln("sum = " + sum);
21 } catch (InterruptedException e) {
22 eprintStackTrace();
23 } catch (ExecutionException e) {
24 eprintStackTrace();
25 }
26
27 }
28 }
29
30
31 class MyCallable implements Callable<Integer> {
32 private int i = 0;
33
34 // 与run()方法不同的是,call()方法具有返回值
35 @Override
36 public Integer call() {
37 int sum = 0;
38 for (; i < 100; i++) {
39 Systemoutprintln(ThreadcurrentThread()getName() + " " + i);
40 sum += i;
41 }
42 return sum;
43 }
44
45 }
复制代码
首先,我们发现,在实现Callable接口中,此时不再是run()方法了,而是call()方法,此call()方法作为线程执行体,同时还具有返回值!在创建新的线程时,是通过FutureTask来包装MyCallable对象,同时作为了Thread对象的target。那么看下FutureTask类的定义:
1 public class FutureTask<V> implements RunnableFuture<V> {
2
3 //
4
5 }
1 public interface RunnableFuture<V> extends Runnable, Future<V> {
2
3 void run();
4
5 }
于是,我们发现FutureTask类实际上是同时实现了Runnable和Future接口,由此才使得其具有Future和Runnable双重特性。通过Runnable特性,可以作为Thread对象的target,而Future特性,使得其可以取得新创建线程中的call()方法的返回值。
执行下此程序,我们发现sum = 4950永远都是最后输出的。而“主线程for循环执行完毕”则很可能是在子线程循环中间输出。由CPU的线程调度机制,我们知道,“主线程for循环执行完毕”的输出时机是没有任何问题的,那么为什么sum =4950会永远最后输出呢?
原因在于通过ftget()方法获取子线程call()方法的返回值时,当子线程此方法还未执行完毕,ftget()方法会一直阻塞,直到call()方法执行完毕才能取到返回值。
上述主要讲解了三种常见的线程创建方式,对于线程的启动而言,都是调用线程对象的start()方法,需要特别注意的是:不能对同一线程对象两次调用start()方法。
你好,本题已解答,如果满意
请点右下角“采纳答案”。
1、通过继承Thread类创建线程
(1)首先定义一个类去继承Thread父类,重写父类中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。
(2)直接创建一个ThreadTest类的对象,也可以利用多态性,变量声明为父类的类型。
(3)调用start方法,线程启动,隐含的调用run()方法。
[java] view plain copy
public class ThreadTest extends Thread{
public void run(){
for(int i=0;i<=10;i++){
Systemoutprintln(i);
}
}
public static void main(String[] args) {
ThreadTest thread1=new ThreadTest();
ThreadTest thread2=new ThreadTest();
thread1start();
thread2start();
}
}
2、通过实现Runnable接口创建线程
(1)定义一个类实现Runnable接口,重写接口中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。
(2)创建Runnable接口实现类的对象。
(3)创建一个ThreadTest类的对象,需要封装前面Runnable接口实现类的对象。(接口可以实现多继承)
(4)调用Thread对象的start()方法,启动线程
[java] view plain copy
public class ThreadTest implements Runnable{
@Override
public void run() {
for(int i=0;i<=10;i++){
Systemoutprintln(i);
}
}
public static void main(String[] args) {
ThreadTest threadTest=new ThreadTest();
Thread theard=new Thread(threadTest);
theardstart();
}
}
3通过Callable和Future创建线程
(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
[java] view plain copy
public class ThreadTest implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int count =0;
for(int i=0;i<=10;i++){
count=count+i;
}
return count;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
ThreadTest test=new ThreadTest();
FutureTask<Integer> thread = new FutureTask<>(test);
new Thread(thread,"有返回值的线程")start();
Systemoutprintln(threadget());
}
}
使用实现Runnable接口方式创建线程可以共享同一个目标对象(TreadDemo1 tt=new TreadDemo1();),实现了多个相同线程处理同一份资源。
然后再看一段来自JDK的解释:
The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread The class must define a method of no arguments calledrun
This interface is designed to provide a common protocol for objects that wish to execute code while they are active For example,Runnable is implemented by classThread Being active simply means that a thread has been started and has not yet been stopped
In addition, Runnable provides the means for a class to be active while not subclassingThread A class that implementsRunnable can run without subclassingThread by instantiating aThread instance and passing itself in as the target In most cases, theRunnable interface should be used if you are only planning to override therun() method and no otherThread methods This is important because classes should not be subclassed unless the programmer intends on modifying or enhancing the fundamental behavior of the class
采用实现Runnable、Callable接口的方式创见多线程时,优势是:
线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
劣势是:
编程稍微复杂,如果要访问当前线程,则必须使用ThreadcurrentThread()方法。采用继承Thread类方式:
(1)优点:编写简单,如果需要访问当前线程,无需使用ThreadcurrentThread()方法,直接使用this,即可获得当前线程。
(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。
采用实现Runnable接口方式:
(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用ThreadcurrentThread()方法。
多线程有三种常见的实现方式:
1 继承Thread类,重写run方法。
2 实现Runnable接口,重写run方法。
3 通过实现Callable接口和使用FutureTask包装器来实现线程
/
通过自己的类直接继承(extend) Thread,并复重写run()方法,就可以通过Thread类的start()方法启动线程,并执行自己定义的run()方法。Thread类的start()方法是启动线程的唯一方法。
@author Lucky
/
public class myThread_1 extends Thread{
public void run(){
Systemoutprintln("方法1:继承Thread类,重写run方法");
}
public static void main(String args[]){
myThread_1 m1=new myThread_1();
myThread_1 m2=new myThread_1();
m1start();
m2start();
}
}
/
通过实现Runnable接口,重写run方法,将接口的实现类的实例作为参数传入带参的Thread构造函数中,然后就可以通过调用Thread类的start()方法启动线程。
@author Lucky
/
class myt2 implements Runnable{
public void run(){
Systemoutprintln("方法2:通过实现Runnable接口,重写run方法");
}
}
public class myThread_2{
public static void main(String args[]){
//为了启动MyThread_2,
//创建一个Runnable子类的对象,然后把这个对象当作参数传入Thread实例中,
//这样就可以调用start()方法启动线程了。
//start()是Thread类中的方法。
myt2 m=new myt2();
Thread t1= new Thread(m);
t1start();
}
}
/通过Callable和FutureTask创建线程 。 创建Callable接口的实现类 ,并实现Call方法 ;
由Callable<Object>创建一个FutureTask<Object>对象;
FutureTask<Object>是一个包装器,它通过接受Callable<Object>来创建;
由FutureTask<Object>创建一个Thread对象;
最后通过调用Thread类的start()方法启动线程。
@author Lucky
/
import javautilconcurrentCallable;
import javautilconcurrentFutureTask;
public class myThread_3 {
public static void main(String args[]){
Callable<Object> c=new myt3<Object>();
FutureTask<Object> f=new FutureTask<Object>(c);
Thread t=new Thread(f);
tstart();
}
}
//创建Callable接口的实现类,并重写call()方法
@SuppressWarnings("hiding")
class myt3<Object> implements Callable<Object>{
//重写call()方法
public Object call() throws Exception{
Systemoutprintln("方法3:通过实现Callable接口和使用FutureTask包装器来实现线程");
return null;
}
}
核心线程数为0,非核心线程数为MAX_VALUE,
队列不存储值,总认为队列是满的,所以每次执行任务时都会创建非核心线程,非核心线程空闲了超过60秒(默认),就会自动回收。
2newfixedThreadPool 创建定长的线程池
在达到长度之前,每提交一个任务都会创建一个线程,如果达到线程池最大数量,则提交到队列中,在空闲的时候也不会自动回收线程
核心线程数为参数传入,非核心线程数和核心线程数一样,
队列为无界队列,资源有限的时候容易引起OOM
与newSingledThreadPool 不同的是核心线程数不为1
3newSingledThreadPool 创建单一线程执行。
只有一个线程按顺序执行任务,如果这个线程出现异常结束,会有另一个线程取代并按顺序执行。
corepoolsize 核心线程数为1 ,非核心线程数为1 ,
队列为无界队列,
单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。
4newScheduedThreadPool 创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。如果延迟3秒执行或每隔3秒执行一次
核心线程数为 参数设定,非核心线程数为MAX_VALUE
定义了一个DelayedWorkQueue,它是一个有序队列,会通过每个任务按照距离下次执行时间间隔的大小来排序;
线程池执行逻辑说明:
判断核心线程数是否已满,核心线程数大小和corePoolSize参数有关,未满则创建线程执行任务
若核心线程池已满,判断队列是否满,队列是否满和workQueue参数有关,若未满则加入队列中
若队列已满,判断线程池是否已满,线程池是否已满和maximumPoolSize参数有关,若未满创建线程执行任务
若线程池已满,则采用拒绝策略处理无法执执行的任务,拒绝策略和handler参数有关
拒绝策略
拒绝策略 => 默认采用的是AbortPolicy拒绝策略,直接在程序中抛出RejectedExecutionException异常因为是运行时异常,不强制catch,这种处理方式不够优雅。处理拒绝策略有以下几种比较推荐:
在程序中捕获RejectedExecutionException异常,在捕获异常中对任务进行处理。针对默认拒绝策略
使用CallerRunsPolicy拒绝策略,该策略会将任务交给调用execute的线程执行一般为主线程,此时主线程将在一段时间内不能提交任何任务,从而使工作线程处理正在执行的任务。此时提交的线程将被保存在TCP队列中,TCP队列满将会影响客户端,这是一种平缓的性能降低
自定义拒绝策略,只需要实现RejectedExecutionHandler接口即可
如果任务不是特别重要,使用DiscardPolicy和DiscardOldestPolicy拒绝策略将任务丢弃也是可以
public class ThreadTest {
// ScheduledExecutorService scheduledThreadPool = ExecutorsnewScheduledThreadPool(5);
//
// scheduledThreadPoolscheduleAtFixedRate(new Runnable() {
// public void run() {
// Systemoutprintln("delay 1 seconds, and excute every 3 seconds");
//
// }
//
// }, 1, 3, TimeUnitSECONDS);
}
继承Thread类来实现多线程:
当我们自定义的类继承Thread类后,该类就为一个线程类,该类为一个独立的执行单元,线程代码必须编写在run()方法中,run方法是由Thread类定义,我们自己写的线程类必须重写run方法。
run方法中定义的代码为线程代码,但run方法不能直接调用,如果直接调用并没有开启新的线程而是将run方法交给调用的线程执行
要开启新的线程需要调用Thread类的start()方法,该方法自动开启一个新的线程并自动执行run方法中的内容
结果:
java多线程的启动顺序不一定是线程执行的顺序,各个线程之间是抢占CPU资源执行的,所有有可能出现与启动顺序不一致的情况。
CPU的调用策略:
如何使用CPU资源是由 *** 作系统来决定的,但 *** 作系统只能决定CPU的使用策略不能控制实际获得CPU执行权的程序。
线程执行有两种方式:
1抢占式:
目前PC机中使用最多的一种方式,线程抢占CPU的执行权,当一个线程抢到CPU的资源后并不是一直执行到此线程执行结束,而是执行一个时间片后让出CPU资源,此时同其他线程再次抢占CPU资源获得执行权。
2轮循式;
每个线程执行固定的时间片后让出CPU资源,以此循环执行每个线程执行相同的时间片后让出CPU资源交给下一个线程执行。
java多线程的几种实现方式:
1继承Thread类,重写run方法
2实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target
3通过Callable和FutureTask创建线程
4通过线程池创建线程 (上一篇已经讲过了)
前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式的返回值是void,所以没有办法返回结果
后面两种可以归结成一类:有返回值,通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中
以上就是关于C++线程的几种调用方式全部的内容,包括:C++线程的几种调用方式、在Java 中多线程的实现方法有哪些,如何使用、创建多线程有几种方法等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)