JUC并发编程(1)——创建线程的几种方式

一、线程基础知识

1.线程的几种状态

操作系统层面
线程的生命周期分为以下五个状态:

  • 新建:当创建了一个Thread类或其子类时,在没调用start()方法前,该线程对象处于新建状态。
  • 就绪:当新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它具备了运行的条件,但是没有分配到CPU资源。
  • 运行:就绪状态的线程被调度并获得CPU资源,运行run()方法操作。
  • 阻塞:在某种情况下,被挂起,让出CPU资源并停止自己的执行,进入阻塞状态。
  • 死亡:线程完成了全部工作或者线程被提前强制性中止或异常导致结束。
    请添加图片描述
    JavaApi层面层面

Java在Thread中定义了一个枚举类,该类中定义了线程六种状态:

  • new
  • runnable
  • timed_waiting :调用sleep后阻塞
  • waiting: 调用其他线程的join后,当前线程waiting
  • blocked: 没抢到锁
  • terminated:停止

2.Thread类的有关方法常用方法

start(): 启动线程,并执行线程对象的run()方法
run(): 线程在被调度时执行的操作
getName():返回线程名称
setName(String name):设置线程名称
static Thread currentThread():返回当前线程,在Thread子类中相当于this
yield():释放当前cpu的执行权,释放后从Running进入Runnable状态,会继续争取cpu调度。
join():阻塞当前线程,改为执行调用join的线程,直到调用join的线程执行完成才会执行当前线程。join(int millis),可以设置等待时间,到达等待时间就不等。
isInterrupted():获取打断标记,并且调用完该方法后不会重置打断标记。Interrupted()方法也是获取打断标记,但是该方法会在获取完后重置打断标记。
interrupt():打断调用该方法的thread对象线程,如果该线程处在阻塞状态,则抛出InterruptedException异常,但是会将打断标记设置为false。如果该线程出在非阻塞状态,则会将打断标记设置为true;
stop():当执行此方法时,强制结束当前线程。不安全,无法关闭线程资源。并且会直接释放锁,会产生线程安全问题。
sleep():睡眠当前线程,单位毫秒
isAlive():判断当前线程是否存活

3.线程的优先级

高优先级的线程抢占CPU。
线程的优先等级
MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5 默认优先级
涉及方法
getPriority():放回当前线程优先级
setPriority(int):改变当前线程的优先级
说明
线程创建时继承父线程的优先级
低优先级只是获得调度的概率低,并非一定是在高优先级之后才被调用

4.系统命令

Windows命令
tasklist:查看进程,显示PID和内存占用
taskkill:/F /PID 333,杀死333进程

Java命令
jps:查看所有java进程

Linux命令
ps -ef:查看进程
kill 333:杀死333进程
top:动态显示进程信息
top -H -p 333:动态查看333进行中的线程信息

5.守护线程

只要其他非守护线程结束了,即使守护线程的代码没有执行完,也会强制结束。

Thread t1 = new Thread(()->{});
t1.setDaemon(true);
t1.start();

6.常见线程安全类

线程安全的类也就是说:它们的每个方法都是原子的,但是它们多个方法的组合不是原子的。

  • String
  • Integer
  • StringBuffer
  • Random
  • Vector
  • Hashtable
  • java.util.concurrent包下的类

二、创建多线程的几种方法

1.继承Thread类实现多线程

1.创建一个类去继承Thread类。
2.重写该类的run()方法,继承要执行的操作写在run()方法里面。
3.创建该类的对象。
4.调用该对象的start()方法。

public class MyThread extends Thread {
	@Override
	public void run() {
	// 线程要执行的方法
	}
	public static void main(String[] args) {
		Thread myThread1 = new MyThread();    
        Thread myThread2 = new MyThread();     
        myThread1.start();                    
        myThread2.start(); 
        // 也可以通过下述方法创建线程
        Thread myThread3 = new Thread(){
        	@Override
			public void run() {
				// 线程要执行的方法
			}
        }            
	}
}

注意事項:

  • 一个线程对象的start()方法只能被调用一次。
  • 线程内的非静态变量不共享,静态变量共享

2.实现Runnable接口实现多线程

class MyThread implements Runnable{
	@Override
	public void run() {
	// 线程要执行的方法
	}
	public static void main(String[] args) {
		MyThread m = new MyThread();
		Thread myThread1 = new MyThread(m);    
        Thread myThread2 = new MyThread(m);    
        myThread1.start();      
        myThread2.start();   
	}
}

注意事項:

  • 相同Runnable实现类对象创建的 线程内的非静态变量和静态变量都共享

比较
实现Runnable接口没有类单继承的局限性,并且该种方法更适合处理多个线程之间有共享数据的情况。

源码分析
事实上,Thread类本身就继承Runnable接口,并且Thread类中拥有一个Runnable属性。
请添加图片描述
我们之所以可以采用这两种方式,从源码来看原因如下:
start()方法中会调用本地方法 start0(),该方法我们知道会执行Thread中的run()方法,如下。
请添加图片描述
该方法未被重写前,调用的是类中Runnable属性的run()方法,所以我们可以通过实现Runnable接口的方式来进行多线程。
当然继承Thread类后,重写了其中的run()方法,执行的就是重写的run()方法中的内容了,所以继承Thread类的方式也可以。

3.实现Callable接口

Class MyThread implements Callable<Integer>{

	@Override
	public Object call() throw Exception {
	
		// 线程代码
		return null;
	}
}

public static void main(String[] args) {
	MyThread myThread = new MyThread(); 
	
	FutureTask<Integer> futureTask = new FutureTask<Integer>(myThread );
	
	new Thread(futureTask ).start;
	// 阻塞等待结果的返回
	Integerresult = futureTask .get();
}

与Runnable对比

① 相比run()方法,可以有返回值
② 方法可以抛出异常
③支持泛型的返回值
④ 但是需要借助FutureTask类

4.使用线程池

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值