多线程的几种创建方式

先说下线程的几种状态(5种):

新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();

就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;

运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就     绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:

1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;

2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;

3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

 

ps:另线程阻塞wait与sleep的区别:字面意思理解为,wait为等待,直到被唤醒;而sleep为睡眠,直到设定的时间,所以wait需要手动唤醒,而sleep不需要。

ps:stop与interrupt为中断线程:

interrupt:首先说interrupt, 它没有stop那么的粗暴,因为可以用catch捕捉到InterruptedException这个异常。

stop(这个已经被废弃,线程阻塞):获取的资源,获取的锁都不释放,相当于无限期的等待下去了,因此不推荐的。因为此时线程直接终止,没有catch异常的机会, 无法对线程结束这一行为作出任何补救动作。

无论是interrupt还是stop都是不安全的做法,因为如果我们在线程进行时打开了某些资源,那么这样粗暴的结束资源将无法正确关闭

 

多线程的几种创建方式:

1.继承Thread类:

package com.xingsfdz.javabase.thread;

/**
 * 
 * @类名称 ThreadDemo.java
 * @类描述 <pre>多线程创建方式之继承Thread</pre>
 * @作者  xingsfdz xingsfdz@163.com
 * @创建时间 2020年4月7日 下午10:27:12
 * @版本 1.00
 *
 * @修改记录
 * <pre>
 *     版本                       修改人 		修改日期 		 修改内容描述
 *     ----------------------------------------------
 *     1.00 	xingsfdz 	2020年4月7日             
 *     ----------------------------------------------
 * </pre>
 */
public class ThreadDemo {

  public static void main(String[] args) {
      //设置线程名字,不设置则使用默认构造 0 1 2 3...这样
      Thread.currentThread().setName("主线程");
      MyThread myThread = new MyThread();
      myThread.setName("子线程:");
      //开启线程
      myThread.start();
      for(int i = 0;i<5;i++){
          System.out.println(Thread.currentThread().getName() + i);
      }
  }
}

//实现方式之继承Thread
class MyThread extends Thread{
  //重写run()方法
  public void run(){
      for(int i = 0;i < 5; i++){
          System.out.println(Thread.currentThread().getName() + i);
      }
  }
}

//注意:由执行结果可以看出,并非按照顺序,而是通过抢占cpu资源,抢到则执行。

执行结果: 

main thread0
子线程:0
子线程:1
子线程:2
main thread1
子线程:3
main thread2
子线程:4
main thread3
main thread4

 

2.实现Runnable接口

package com.xingsfdz.javabase.thread;

/**
 * 
 * @类名称 RunnableDemo.java
 * @类描述 <pre>实现Runnable接口方式</pre>
 * @作者  xingsfdz xingsfdz@163.com
 * @创建时间 2020年4月7日 下午11:02:54
 * @版本 1.00
 *
 * @修改记录
 * <pre>
 *     版本                       修改人 		修改日期 		 修改内容描述
 *     ----------------------------------------------
 *     1.00 	xingsfdz 	2020年4月7日             
 *     ----------------------------------------------
 * </pre>
 */
public class RunnableDemo {
	
	 public static void main(String[] args) {
	      //设置线程名字,不设置则使用默认构造 0 1 2 3...这样
	      Thread.currentThread().setName("主线程");
	      Thread myThread = new Thread(new MyRunnable());//作为参数传入
	      myThread.setName("实现Runnable接口方式,子线程:");
	      //开启线程
	      myThread.start();
	      for(int i = 0;i<5;i++){
	          System.out.println(Thread.currentThread().getName() + i);
	      }
	  }
	}

	//实现方式之实现Runnable
	class MyRunnable implements Runnable{
	  //重写run()方法
	  public void run(){
	      for(int i = 0;i < 5; i++){
	          System.out.println(Thread.currentThread().getName() + i);
	      }
	  }
	}

结果:

主线程0
实现Runnable接口方式,子线程:0
实现Runnable接口方式,子线程:1
实现Runnable接口方式,子线程:2
主线程1
实现Runnable接口方式,子线程:3
实现Runnable接口方式,子线程:4
主线程2
主线程3
主线程4

 

3.实现Callable接口(带返回值的):

package com.xingsfdz.javabase.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 
 * @类名称 CallableDemo.java
 * @类描述 <pre>带返回值的,实现Callable接口方式</pre>
 * @作者  xingsfdz xingsfdz@163.com
 * @创建时间 2020年4月7日 下午11:29:20
 * @版本 1.00
 *
 * @修改记录
 * <pre>
 *     版本                       修改人 		修改日期 		 修改内容描述
 *     ----------------------------------------------
 *     1.00 	xingsfdz 	2020年4月7日             
 *     ----------------------------------------------
 * </pre>
 */
public class CallableDemo implements Callable<Integer>{

	public static void main(String[] args) {
		CallableDemo demo = new CallableDemo();
		//执行Callable 方式,需要FutureTask 实现实现,用于接收运算结果
		FutureTask<Integer> task = new FutureTask<>(demo);//代码规范,泛型写一边即可。
		Thread t = new Thread(task);
		t.start();
		System.out.println("主线程可以做点别的,等待demo计算的返回结果,下面设置了2秒的等待");
		Integer res = 0;
		try {
			res = task.get();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("通过实现接口方式线程返回结果:" + res);
	}

	//相当于 Thread里面的run()方法
	@Override
	public Integer call() throws Exception {
		System.out.println("业务处理...");
		Thread.sleep(2000);//毫秒
		return 1;//返回值
	}

}

执行结果:

主线程可以做点别的,等待demo计算的返回结果,下面设置了2秒的等待
业务处理...
通过实现接口方式线程返回结果:1

 

4.使用线程池:

package com.xingsfdz.javabase.thread;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * 
 * @类名称 ThreadPoolDemo.java
 * @类描述 <pre>线程池方式创建线程</pre>
 * @作者  xingsfdz xingsfdz@163.com
 * @创建时间 2020年4月8日 下午1:50:18
 * @版本 1.00
 *
 * @修改记录
 * <pre>
 *     版本                       修改人 		修改日期 		 修改内容描述
 *     ----------------------------------------------
 *     1.00 	xingsfdz 	2020年4月8日             
 *     ----------------------------------------------
 * </pre>
 */
public class ThreadPoolDemo {

	public static void main(String[] args) {
		//Executor还有其他很多之类,可以根据 自己需求使用
		Executor threadPool = Executors.newFixedThreadPool(5);//创建一个5个线程的线程池
		//向线程池里面提交10个任务
		for(int i = 0;i < 10; i++){
			threadPool.execute(new Runnable(){
					@Override
					public void run() {
						System.out.println(Thread.currentThread().getName());
					}
			});
		}
	}
}

运行结果:

pool-1-thread-1
pool-1-thread-5
pool-1-thread-4
pool-1-thread-2
pool-1-thread-3
pool-1-thread-2
pool-1-thread-4
pool-1-thread-5
pool-1-thread-1
pool-1-thread-3

结论:可以发现,任务使用的线程始终是创建的线程池里面的五个线程。而不是十个线程,五个线程循环使用,处理完了,继续处理下一个任务。 

 

5.匿名内部类方式创建(适合只使用一次,不需要知道类名的)

 

6.定时器

package com.xingsfdz.javabase.thread;

import java.util.Timer;
import java.util.TimerTask;

/**
 * 
 * @类名称 QuartzDemo.java
 * @类描述 <pre>多线程创建定时器方式</pre>
 * @作者  xingsfdz xingsfdz@163.com
 * @创建时间 2020年4月7日 下午11:08:25
 * @版本 1.00
 *
 * @修改记录
 * <pre>
 *     版本                       修改人 		修改日期 		 修改内容描述
 *     ----------------------------------------------
 *     1.00 	xingsfdz 	2020年4月7日             
 *     ----------------------------------------------
 * </pre>
 */
public class QuartzDemo {
	
	public static void main(String [] args){
		Timer timer = new Timer();
		
		//使用内部类方式演示
		timer.schedule(new TimerTask(){

			@Override
			public void run() {
				System.out.println("使用timertask 方式运行线程...");
			}
			
		}, 0, 1000);//单位毫秒,此处标识相隔1s
	}

}
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...
使用timertask 方式运行线程...

 

7.Lambda(可以代替内部类的方式)

package com.xingsfdz.javabase.thread;

import java.util.Arrays;
import java.util.List;

/**
 * 
 * @类名称 LambdaDemo.java
 * @类描述 <pre>使用Lambda方式处理</pre>
 * @作者  xingsfdz xingsfdz@163.com
 * @创建时间 2020年4月8日 下午2:08:31
 * @版本 1.00
 *
 * @修改记录
 * <pre>
 *     版本                       修改人 		修改日期 		 修改内容描述
 *     ----------------------------------------------
 *     1.00 	xingsfdz 	2020年4月8日             
 *     ----------------------------------------------
 * </pre>
 */
public class LambdaDemo {

	public static void main(String[] args) {

		List<Integer> values =  Arrays.asList(10, 20, 30, 40, 50);
		//通常局部变量使用基础类型,类变量使用引用类型
		int res = add(values);
		System.out.println("计算结果:" + res);
	}
	
	public static int add (List<Integer> values){
		//使用Lambda操作流,对集合values
		return values.parallelStream().mapToInt(a -> a).sum();
	}
	
	//注意:我们看源码可以看到 这是1.8 在接口Collection里面新增的一个默认方法。 default Stream<E> parallelStream() 
	//而且通过注释我们也可以看到这是一个并行的方法,不是串行的。

}

运行结果:

计算结果:150

或者: 

 

package com.xingsfdz.demo.util.lambda;

public class TestLamInfaImpl implements TestLamInfa, Runnable{
	
	public static void main(String args[]){
		TestLamInfaImpl test = new TestLamInfaImpl();
		test.run();//传统的 需要手动实现Runnable
		testLambda();//Lambda方式,一句话搞定,不需要手动实现Runnable接口(函数式接口,隐式实现)
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("传统写法的实现Runnable接口的线程");
	}
	
	//语法格式一:无参数,无返回值的方式,还有别有参有返回值的方式
	public static void testLambda(){
		Runnable runnable = () ->System.out.println("Lambda方式启动线程");
		runnable.run();
	}

}

结果: 

传统写法的实现Runnable接口的线程
Lambda方式启动线程

 

8.Spring实现多线程:

使用java代码配置:Config.java

package com.xingsfdz.demo.util.Thread.spring;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

/**
 * 
 * @类名称 Config.java
 * @类描述 <pre>一下操作相当于我们前期的spring配置文件的操作</pre>
 * @作者  xingsfdz xingsfdz@163.com
 * @创建时间 2020年4月8日 下午2:18:47
 * @版本 1.00
 *
 * @修改记录
 * <pre>
 *     版本                       修改人 		修改日期 		 修改内容描述
 *     ----------------------------------------------
 *     1.00 	xingsfdz 	2020年4月8日             
 *     ----------------------------------------------
 * </pre>
 */
//标识为配置文件
@Configuration
//扫描的包
@ComponentScan("com.xingsfdz.demo.util.Thread.spring")
//支持异步,不使用该注解,则不会执行后面的方法
@EnableAsync
public class Config {

}

编写一个服务类:ServiceDemo  

package com.xingsfdz.demo.util.Thread.spring;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

//注入容器管理
@Service
public class ServiceDemo {

	//注解为支持异步
	@Async
	public void a(){
		while(true){
			System.out.println("处理a方法");
			try {
				Thread.sleep(3000);//单位 毫秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	@Async
	public void b(){
		while(true){
			System.out.println("处理b方法");
			try {
				Thread.sleep(3000);//单位 毫秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

运行测试:

package com.xingsfdz.demo.util.Thread.spring;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 
 * @类名称 SpringDemo.java
 * @类描述 <pre>spring方式多线程</pre>
 * @作者  xingsfdz xingsfdz@163.com
 * @创建时间 2020年4月8日 下午2:15:25
 * @版本 1.00
 *
 * @修改记录
 * <pre>
 *     版本                       修改人 		修改日期 		 修改内容描述
 *     ----------------------------------------------
 *     1.00 	xingsfdz 	2020年4月8日             
 *     ----------------------------------------------
 * </pre>
 */
public class SpringDemo {
	public static void main(String args[]){
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);//加载配置文件
		ServiceDemo sd = ac.getBean(ServiceDemo.class);//获得类实例对象
		sd.a();
		sd.b();
	}
}

 运行结果:循环执行表示异步执行成功

 

### 回答1: 在Python中,有两种常用的创建多线程方式: 1. 使用threading模块创建线程。可以通过创建Thread对象并将一个函数作为目标来创建新线程。例如: ``` import threading def my_function(): # 代码块 my_thread = threading.Thread(target=my_function) my_thread.start() ``` 2. 继承Thread类创建线程。可以创建一个新的类,继承Thread类,并实现run()方法来定义线程的行为。例如: ``` import threading class MyThread(threading.Thread): def run(self): # 代码块 my_thread = MyThread() my_thread.start() ``` ### 回答2: 创建多线程方式有三种:使用继承Thread类的方式、实现Runnable接口的方式和使用Executor框架的方式。 第一种方式是通过继承Thread类来创建多线程。首先定义一个继承自Thread类的子类,然后重写run()方法,在run()方法中编写线程的逻辑代码。通过子类的实例化对象调用start()方法启动线程。这种方式创建的线程较为简单,但是由于Java只支持单继承,所以当一个类已经继承了其他类时,无法使用这种方式创建多线程。 第二种方式是通过实现Runnable接口来创建多线程。定义一个实现了Runnable接口的类,实现类重写run()方法,在run()方法中编写线程的逻辑代码。然后通过实例化一个Thread对象,将实现类的对象作为参数传入Thread的构造方法中,并调用Thread的start()方法启动线程。这种方式避免了Java单继承的限制,并且线程与任务的分离,解耦更好,所以在实际开发中更常使用这种方式创建多线程。 第三种方式是使用Executor框架来创建多线程。Executor框架是JDK提供的一种用于管理和调度线程的框架。通过创建一个ExecutorService对象,然后使用线程池的方式创建多线程。可以使用Executors类的静态方法来创建不同类型的线程池。这种方式可以实现线程的池化管理,可以灵活控制线程的数量,并且可以提供更好的性能和资源的管理。 ### 回答3: 创建多线程方式有三种: 1. 继承Thread类:通过定义一个类继承自Thread类,重写run方法,在run方法中实现线程的具体逻辑。通过创建该类的对象,可以启动新的线程。 2. 实现Runnable接口:定义一个类实现Runnable接口,实现接口中的run方法,在run方法中实现线程的具体逻辑。通过创建该类的对象,并将其作为参数传递给Thread类的构造方法,并调用线程对象的start方法,启动新的线程。 3. 使用Executor框架:使用Java提供的Executor框架,通过调用ExecutorService的方法,可以创建并管理线程池。通过提交实现Runnable接口或Callable接口的任务给线程池,框架会自动创建新的线程并执行任务。 这三种方式各有优缺点,继承Thread类方式比较简单,但耦合性较高,不便于复用;实现Runnable接口方式可以实现资源共享,适用于多个线程共享一个资源的场景;使用Executor框架则可以更方便地管理线程和任务,提供更多的控制和灵活性。 在选择创建多线程方式时,需要根据具体的应用场景和需求来选择最合适的方式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值