java 多线程的三种构建方法
java 多线程的三种构建方法
继承Thread类创建线程类
publicclassThreadextendsObjectimplementsRunnable
- 定义Thread类的子类,并重写其run()方法
- 创建Thread子类的实例,即创建了线程对象
- 调用线程对象的start()方法启动线程
publicclassFirstThreadextendsThread{
publicvoidrun(){
for(inti=0;i<100;i++){
/*
*Thread类已经继承了Object
*Object类创建了name选项并且有其getName(),setName()方法
*在继承Thread的类里面使用时只需要用this引用
*/
System.out.println(this.getName()+""+i);
}
}
publicstaticvoidmain(String[]args){
for(inti=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+""+i);
if(i==20){
newFirstThread().start();
newFirstThread().start();
}
}
}
}
Thread类已经继承了Object
Object类创建了name选项并且有其getName(),setName()方法
在继承Thread的类里面使用时只需要用this引用
上面两个副线程和主线程随机切换,又因为使用的是继承Thread的类所以两个副线程不能共享资源
start()方法调用后并不是立即执行多线程代码,而是使得该线程编程可运行状态,什么时候运行是由操作系统决定的
实现Runnable接口创建线程类
publicThread() publicThread(Runnabletarget) publicThread(Runnabletarget,Stringname)
- 定义Runnable接口的实现类,并重写该接口的run()方法
- 创建Runnable实现类的实例,并以此作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
publicclassSecondThreadimplementsRunnable{
publicvoidrun(){
for(inti=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+""+i);
}
}
publicstaticvoidmain(String[]args){
for(inti=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+""+i);
if(i==20){
SecondThreadst=newSecondThread();
//通过newThread(target,name)创建线程
newThread(st,"新线程1").start();
newThread(st,"新线程2").start();
}
}
}
}
上面的结果是两个副线程和主线程随机切换,但是并没有共享资源,因为他们根本没有能用来共享的资源。
start()方法调用后并不是立即执行多线程代码,而是使得该线程编程可运行状态,什么时候运行是由操作系统决定的
继承Thread类和创建Runnable接口的共享资源详解
在只有可以用来共享的资源时候,也就是同用一个实例化对象。两个创建方式在共享资源时才会有所区别,否则它们都不会共享资源共享资源通常用privatestatic修饰符来修饰。
classThread1extendsThread{
privateintcount=5;
privateStringname;
publicThread1(Stringname){
this.name=name;
}
publicvoidrun(){
for(inti=0;i<5;i++){
System.out.println(name+"运行count="+count--);
try{
sleep((int)Math.random()*10);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
publicclassMain{
publicstaticvoidmain(String[]args){
Thread1mTh1=newThread1("A");
Thread1mTh2=newThread1("B");
mTh1.start();
mTh2.start();
}
}
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
正是因为有了privateintcount=5;一句才有了共享资源,但这是继承Thread类的子类,并不能共享资源
classThread2implementsRunnable{
privateintcount=15;
publicvoidrun(){
for(inti=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"运行count="+count--);
try{
Thread.sleep((int)Math.random()*10);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
publicclassMain{
publicstaticvoidmain(String[]args){
Thread2my=newThread2();
newThread(my,"C").start();//同一个mt,但是在Thread中就不可以,如果用同一个实例化对象mt,就会出现异常
newThread(my,"D").start();
newThread(my,"E").start();
}
}
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
同样的正是因为有了privateintcount=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()方法来获得子线程结束后的返回值
publicclassThirdThreadimplementsCallable{ publicIntegercall(){ inti=0; for(;i<100;i++){ System.out.println(Thread.currentThread().getName()+""+i); } returni; } publicstaticvoidmain(String[]args){ ThirdThreadtt=newThirdThread(); FutureTask task=newFutureTask<>(tt); Threadt=newThread(task,"有返回值的线程"); for(inti=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+""+i); if(i==20){ t.start(); } } try{ System.out.println("返回值是:"+task.get()); }catch(Exceptione){ e.printStackTrace(); } } }
使用Lambda表达式的Callable和Future创建的线程
publicclassThirdThread{
publicstaticvoidmain(String[]args){
ThirdThreadtt=newThirdThread();
//先使用Lambda表达式创建Callable对象
//使用FutureTask封装Callable对象
FutureTasktask=newFutureTask((Callable)()->{
inti=0;
for(;i<100;i++){
System.out.println(Thread.currentThread().getName()+"的循环变量i的值:"+i);
}
returni;
});
for(inti=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+"的循环变量i的值:"+i);
if(i==20){
newThread(task,"有返回值的线程").start();
}
}
try{
System.out.println("子线程的返回值"+task.get());
}catch(Exceptione){
e.printStackTrace();
}
}
}
如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!