Java之多线程详解

小结:

多线程有几种实现方案,分别是哪几种?

         a, 继承Thread类(重写run方法)

         b, 实现Runnable接口(重写run方法)

         c, 通过线程池,实现Callable接口(submit方法调用结束后,线程不会结束,因为线程池控制了线程)

            //创建线程池对象
		ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
		//创建Callable实例对象
		
              MyCallable r = new MyCallable();		
                service.submit(r);
                service.submit(r);
public class MyCallable implements Callable {
	public Object call() throws Exception {   //call方法可以有返回值
		方法
	}
}

多线程

进程与线程

进程:指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。


线程:进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。(多个方法可以同时运行


               

总结:一个程序运行后至少有一个进程,一个进程中可以包含多个线程

单线程与多线程


线程创建

方式一:继承Thread类,重写run方法

public class Demo {
	public static void main(String[] args) {
		//创建自定义线程对象
		MyThread mt = new MyThread("新的线程!");
		//开启新线程
		mt.start();
		//在主方法中执行for循环
		for (int i = 0; i < 10; i++) {
			System.out.println("main线程!"+i);
		}
	}
}
public class MyThread extends Thread {
	//定义指定线程名称的构造方法
	public MyThread(String name) {
		//调用父类的String参数的构造方法,指定线程的名称
		super(name);
	}
	/**
	 * 重写run方法,完成该线程执行的逻辑
	 */
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(getName()+":正在执行!"+i);
		}
	}
}

方式二:实现Runnable接口,重写run方法

public class Demo{
	public static void main(String[] args) {
		//创建线程执行目标类对象
		Runnable runn = new MyRunnable();
		//将Runnable接口的子类对象作为参数传递给Thread类的构造函数
		Thread thread = new Thread(runn);
		Thread thread2 = new Thread(runn);
		//开启线程
		thread.start();
		thread2.start();
		for (int i = 0; i < 10; i++) {
			System.out.println("main线程:正在执行!"+i);
		}
	}
}
public class MyRunnable implements Runnable{

	//定义线程要执行的run方法逻辑
	@Override
	public void run() {
		
		for (int i = 0; i < 10; i++) {
			System.out.println("我的线程:正在执行!"+i);
		}
	}
}

线程的匿名内部类

方式一:Thread方式

	new Thread() {
			public void run() {
				for (int x = 0; x < 40; x++) {
					System.out.println(Thread.currentThread().getName()
							+ "...X...." + x);
				}
			}
		}.start();

方式二:Runnable方式

Runnable r = new Runnable() {
			public void run() {
				for (int x = 0; x < 40; x++) {
					System.out.println(Thread.currentThread().getName()
							+ "...Y...." + x);
				}
			}
		};
		new Thread(r).start();

Thread和Runnable方式的区别

1:避免了单继承的局限性,所以较为常用。

2:降低了代码的耦合性。将线程与任务分离。(调用时,是新建一个线程,将Runnable接口实现类进行传参)实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。继承Thread类,线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象,既是线程对象,有又有线程任务。实现runnable接口,将线程任务单独分离出来封装成对象,类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。

线程原理

每个线程都会单独开一个栈空间

线程池

线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。(创建和销毁线程花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多)

线程池使用方式

方式一:Runnable接口(无返回值不可抛异常,因为Runnable本身未抛出异常,实现类不可抛)

 1:创建线程池对象

 2:创建Runnable接口子类对象

 3:提交Runnable接口子类对象

 4:关闭线程池

public class ThreadPoolDemo {
	public static void main(String[] args) {
		//创建线程池对象
		ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
		//创建Runnable实例对象
		MyRunnable r = new MyRunnable();
		
		//自己创建线程对象的方式
		//Thread t = new Thread(r);
		//t.start(); ---> 调用MyRunnable中的run()
		
		//从线程池中获取线程对象,然后调用MyRunnable中的run()
		service.submit(r);
		//再获取个线程对象,调用MyRunnable中的run()
		service.submit(r);
		service.submit(r);
//注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。将使用完的线程又归还到了线程池中

//关闭线程池
		//service.shutdown();
	}
public class MyRunnable implements Runnable {
	@Override
	public void run() {
		System.out.println("我要一个教练");
		
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("教练来了: " +Thread.currentThread().getName());
		System.out.println("教我游泳,交完后,教练回到了游泳池");
	}
}
方式二:Callable接口(返回值可抛异常,因为Callable已经抛出异常,实现类可抛可不抛)

1:创建线程池对象

2:创建Callable接口子类对象

3:提交Callable接口子类对象

4:关闭线程池

public class ThreadPoolDemo {
	public static void main(String[] args) {
		//创建线程池对象
		ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
		//创建Callable对象
		MyCallable c = new MyCallable();
		
		//从线程池中获取线程对象,然后调用MyRunnable中的run()
		service.submit(c);
		
		//再获取个教练
		service.submit(c);
		service.submit(c);
//注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。将使用完的线程又归还到了线程池中

                //关闭线程池
		//service.shutdown();
	}
}
public class MyCallable implements Callable {
	@Override
	public Object call() throws Exception {
		System.out.println("我要一个教练:call");
		Thread.sleep(2000);
		System.out.println("教练来了: " +Thread.currentThread().getName());
		System.out.println("教我游泳,交完后,教练回到了游泳池");
		return null;
	}
}
线程池练习:返回两个数相加的结果
public class ThreadPoolDemo {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//创建线程池对象
		ExecutorService threadPool = Executors.newFixedThreadPool(2);
		
		//创建一个Callable接口子类对象
		//MyCallable c = new MyCallable();
		MyCallable c = new MyCallable(100, 200);
		MyCallable c2 = new MyCallable(10, 20);
		
		//获取线程池中的线程,调用Callable接口子类对象中的call()方法, 完成求和操作
		//<Integer> Future<Integer> submit(Callable<Integer> task)
		// Future 结果对象
		Future<Integer> result = threadPool.submit(c);
		//此 Future 的 get 方法所返回的结果类型
		Integer sum = result.get();
		System.out.println("sum=" + sum);
		
		//再演示
		result = threadPool.submit(c2);
		sum = result.get();
		System.out.println("sum=" + sum);
		//关闭线程池(可以不关闭)
		
	}
}
public class MyCallable implements Callable<Integer> {
	//成员变量
	int x = 5;
	int y = 3;
	//构造方法
	public MyCallable(){
	}
	public MyCallable(int x, int y){
		this.x = x;
		this.y = y;
	}

	@Override
	public Integer call() throws Exception {
		return x+y;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值