多线程_1_简介+实现

本文介绍了Java中实现多线程的三种方式:继承Thread类、实现Runnable接口以及实现Callable接口。详细讲解了每个方法的实现过程和优缺点,包括start()和run()的区别,以及线程的常用方法如sleep()、yield()和join()。文章还探讨了线程池的概念,并对多线程实现方式进行了总结。
摘要由CSDN通过智能技术生成

1:多线程简介

不同程序块一起运行,多任务处理机制

所谓多线程是指一个进程在执行过程中可以产生多个线程,这些线程可以同时存在、同时运行,形成多条执行线。一个进程可能包含了多个同时执行的线程

1:进程:一个正在运行的程序就是一个进程

程序: 是为了完成特定任务,用某种语言编写的一组指令的集合,即指一段静态的代码,

每个独立执行的程序称为进程

2:线程:在应用程序中的执行路径

线程是比进程更小的执行单位。

线程是CPU调度和分派的基本单位

线程是进程内部单一的一个顺序控制流,所谓多线程是指一个进程在执行过程中可以产生多个线程,这些线程可以同时存在、同时运行,形成多条执行线。一个进程可能包含了多个同时执行的线程。

3 :进程与线程的关系

进程的产生,肯定会产生至少一个以上的线程;

进程关闭,该进程内的线程会全部销毁;

线程销毁,进程未必会关闭

一个进程有多个线程。

多线程是实现并发机制的一种有效手段。进程和线程一样,都是实现并发的一个基本单位

线程和进程的主要差别体现如下:

区别

进程:每个进程都有自己独立的代码和数据空间,进程间的切换开销大

线程:一个进程内的多个线程,共享代码和数据空间,线程间的切换开销比较小

2:多线程-实现

多线程,指的是一个进程内的多个任务并发执行;

多线程的好处:可以更高效地利用CPU资源,同时,让固定流程的程序更加灵活;

注意:多个线程之间,谁先抢占到资源,谁就先执行

1: 继承Thread类

线程的操作首先一定要有一个线程的主体操作类,这个主体操作类就可以通过继承Thread类来完成,而继承Thread类之后还要去覆写Thread类中的run()方法,此方法的功能与main()方法类似,属于线程的启动点.


/*
* 1:编写一个类,继承自Thread类
* 2:重写run方法
* */
public class MyThread extends Thread{

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name+"执行run方法的线程");
    }
}
public class Test1 {

    public static void main(String[] args) {

        MyThread myThread1 = new MyThread();
        myThread1.start();
        MyThread myThread2 = new MyThread();
        myThread2.start();
        MyThread myThread3 = new MyThread();
        myThread3.start();

    }
}

start()方法执行,首先做一个判断,这里是判断该线程是否已经启动了,如果是已经启动的线程,会报IllegalThreadStateException异常

结论:线程不允许重复启动

在多线程使用时,要想启动多线程,必须通过start()方法

2: 实现Runnable接口

多线程类实现Runnable接口后,还是需要Thread类下的start()方法来启动线程

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name+"获取当前线程对象");
    }
}

class Test2{
    public static void main(String[] args) {

        MyRunnable r1 = new MyRunnable();
        MyRunnable r2 = new MyRunnable();
        MyRunnable r3 = new MyRunnable();
        new Thread(r1).start();
        new Thread(r2).start();
        new Thread(r3).start();

    }
}

3 :实现Callable接口

1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。

(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。

(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。

(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

//java并发工具包
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class MyCallable implements Callable<Integer> {

	//先继承Callable类,重写call方法
    @Override
    public Integer call() throws Exception {
        String name = Thread.currentThread().getName();
        System.out.println(name+"执行了");

        Thread.sleep(10000);

        return 1024;
    }
}

class Test3{
    public static void main(String[] args) throws Exception {

        MyCallable myCallable = new MyCallable();
        /*
        * 创建一个FutureTask,线程start执行call方法
        * */
        FutureTask futureTask = new FutureTask(myCallable);
        new Thread(futureTask).start();

        Integer result = (Integer) futureTask.get();
        System.out.println("获取线程执行的结果"+result);

        System.out.println("main.....");

    }
}

eg.2.0版本

package Thread;

import java.util.concurrent.*;

public class TestThread {
public static void main(String[] args) throws Exception {
   testCallable();
}

public static void testCallable() throws Exception {
   Callable callable = new MyThreadCallable();
   FutureTask task = new FutureTask(callable);
   new Thread(task).start();
   System.out.println(task.get());
   Thread.sleep(10);//等待线程执行结束
   //task.get() 获取call()的返回值。若调用时call()方法未返回,则阻塞线程等待返回值
   //get的传入参数为等待时间,超时抛出超时异常;传入参数为空时,则不设超时,一直等待
   System.out.println(task.get(100L, TimeUnit.MILLISECONDS));
}
}

class MyThreadCallable implements Callable {

@Override
public Object call() throws Exception {
   System.out.println("通过实现Callable,线程号:" + Thread.currentThread().getName());
   return 10;
}
}

4:三种实现的区别

  • 采用继承Thread类方式:

   (1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。    

           (2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。

  • 采用实现Runnable接口方式:

   (1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。    

           (2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。

  • Runnable和Callable的区别:

   (1)Callable规定的方法是call(),Runnable规定的方法是run().    

           (2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得    

           (3)call方法可以抛出异常,run方法不可以,因为run方法本身没有抛出异常,所以自定义的线程类在重写run的时候也无法抛出异常    

           (4)运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。

!!!

目录

1:多线程简介

1:进程:一个正在运行的程序就是一个进程

2:线程:在应用程序中的执行路径

3 :进程与线程的关系

2:多线程-实现

1: 继承Thread类

2: 实现Runnable接口

3 :实现Callable接口

4:三种实现的区别

!!!max:start()和run()的区别

5:线程的常用方法

6.yield()和join()

6.1:yieId()

6.2:join()

3:总结

3.1:多线程的三种实现方式+线程池:

3.2:三种实现的区别

3.3:start()和run()的区别

3.4:yield()和join()

4、建议采纳


max:start()和run()的区别

  • start()方法用来,开启线程,但是线程开启后并没有立即执行,他需要获取cpu的执行权才可以执行

  • run()方法是由jvm创建完本地操作系统级线程后回调的方法,不可以手动调用(否则就是普通方法)

5:线程的常用方法

Thread.sleep(毫秒数),让线程休眠,时间到,自动唤醒并继续执行

Thread.currentThread():表示获取当前正在执行的线程对象

getName():获取线程名字

public finalboolean isAlive():测试线程是否处于活动状态

优先级:可以给线程设置优先级,范围是1-10,10优先级最高

setPriority(数字):给线程设置优先级,这里优先级高,并不代表一定先执行,只是增加了抢占到资源的机会

getPriority():获取线程的优先级,

------------------------------------------

Thread提供了三个优先级常量:

Thread.MAX_PRIORITY=10

NORM_PRIORITY = 5

MIN_PRIORITY = 1

Main方法的优先级,是5

6.yield()和join()

yield():当前线程暂停执行,与其他线程同时抢占资源,如果还是自己抢占到,则继续执行后续的代码,如果是其他线程抢占到,则其他线程先执行.

join():当前线程暂停执行,新加入的线程开始执行,当新线程执行完之后,再执行当前线程

6.1:yieId()

先准备一个A线程,在执行A线程过程中准备B线程,并让B线程就绪,然后A线程执行到一半之后,A线程礼让,此时A和B都就绪,然后各自抢占资源,谁抢到资源谁执行,如下:

//A线程代码如下:
package cn.sz.gl.test02;

public class MyRunA implements Runnable {

	@Override
	public void run() {
		MyRunB b = new MyRunB();
		Thread tb = new Thread(b,"B");
		tb.start();
		System.out.println("线程A启动..");
		Thread.currentThread().yield();
		
		System.out.println("线程A结束..");
	}

}
//B线程如下:
package cn.sz.gl.test02;

public class MyRunB implements Runnable {

	@Override
	public void run() {
		System.out.println("线程B启动..");
		System.out.println("线程B结束...");
	}

}
//测试方法如下:
package cn.sz.gl.test02;

public class Test {

	public static void main(String[] args) {
		MyRunA a = new MyRunA();
		Thread ta = new Thread(a,"A");
		ta.start();
	}
}

6.2:join()

先准备一个A线程,在执行A线程过程中准备B线程,并让B线程就绪,然后A线程执行到一半之后,让B线程调用join方法,此时A线程阻塞,B 线程启动执行,当B线程执行完毕后,A线程再继续执行

//A线程代码如下:
package cn.sz.gl.test02;

public class MyRunA implements Runnable {

	@Override
	public void run() {
		MyRunB b = new MyRunB();
		Thread tb = new Thread(b);
		tb.start();
		System.out.println("线程A启动..");
		try {
			tb.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		System.out.println("线程A结束..");
	}

}
//B 线程代码如下:
package cn.sz.gl.test02;

public class MyRunB implements Runnable {

	@Override
	public void run() {
		System.out.println("线程B启动..");
		System.out.println("线程B结束...");
	}

}
//测试代码如下:
package cn.sz.gl.test02;

public class Test {

	public static void main(String[] args) {
		MyRunA a = new MyRunA();
		Thread ta = new Thread(a,"A");
		ta.start();
	}
}


3:总结

3.1:多线程的三种实现方式+线程池:

  • 继承Thread
  • 实现Runable接口
  • 实现Callable接口
  • 线程池

3.2:三种实现的区别

3.3:start()和run()的区别

  • start()方法用来,开启线程,但是线程开启后并没有立即执行,他需要获取cpu的执行权才可以执行

  • run()方法是由jvm创建完本地操作系统级线程后回调的方法,不可以手动调用(否则就是普通方法)

3.4:yield()和join()

yield():当前线程暂停执行,与其他线程同时抢占资源,如果还是自己抢占到,则继续执行后续的代码,如果是其他线程抢占到,则其他线程先执行.

join():当前线程暂停执行,新加入的线程开始执行,当新线程执行完之后,再执行当前线程

4、建议采纳

如有建议或者错误请私信我进行修改,感谢!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值