java多线程——线程的创建和启用

本文介绍了Java中创建线程的两种主要方法:通过继承Thread类和实现Runnable接口,并对比了两者的优缺点。此外,还详细解释了线程从新建到死亡的整个生命周期。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线程的创建和启用

一、通过继承Thread类来创建线程

1、继承Thread,重写run方法,run方法的方法体就代表了县城需要执行的任务

2、创建Thread子类实例,即创建了线程对象

3、调用线程对象.start()方法,启动该线程 

 

//通过继承Thread类来创建线程

publicclass FirstThread extends Thread
{
       private int i;

       //重写run方法,run方法的方法体就是线程的执行体

       public void run
       {
              for(i;i<100;i++)
              {
                     //继承Thread后,可通过getName()直接返回当前线程名;this用于获取当前线程

                     System.out.println(getName()+""+i);
              }            
       }      
}

publicstatic void main(String[] args)
{
       for(int i;i<100,i++)
       {

              //调用Thread的currentThread,currentThread用来获取当前正在执行的线程

              System.out.println(Thread.currentThread().getName()+""+i);

              if(i==20 ) //当i=20时,以下两条线程被创建、启动
              {
                     //创建并启动第一条线程

                     new FirstThread().start();

                     //创建并启动第二条线程

                     new FirstThread().start();                    
              }             

       }

}

二、通过实现Runnable接口创建线程

1、实现Runnable接口,实现run方法

2、通过newThread(st,"新线程1").start();创建并启动线程 

//通过实现Runnable接口创建线程

publicclass SecondThread implements Runnable
{
       private int i;
       //重写run方法,run方法的方法体就是线程的执行体
       public void run
       {
              for(i;i<100;i++)
              {
                    //继承Thread后,只能通过currentThread获得当前线程

                     System.out.println(Thread.currentThread().getName()+""+i)
              }             
       }      
}
publicstatic void main(String[] args)
{
       for(int i;i<100,i++)
       {             
              System.out.println(Thread.currentThread().getName()+""+i);

              if(i==20)
              {
                     //通过newThread(target,name)来创建并启动第一条线程

                     new Thread(st,"新线程1").start();

                     //通过newThread(target,name)来 创建并启动第二条线程

                     new Thread(st,"新线程2").start();
              }
              if(i>20 &&!st.isAlive())//isAlive判断线程状态,死亡态返回false
              {
                    //试图再次启动该线程

                     st.start();
              }
       }
}

通过实现Runnable接口创建的线程SecondThread并非真正的线程对象,只能作为线程对象的target目标,实际上的线程是target类,创建的多条线程共享线程类target实例的属性方法;

而使用第一种方法继承Thread类所创建的线程就是线程对象本身。所以用this可以直接表示当前线程对象。

三、两种创建线程方式对比

创建方式

优点

缺点

实现Runnable接口(常用)

1、   还可继承其他类

2、   多线程共享一个target对象,所以非常适合多个相同线程处理同一份资源

编程相对复杂,必须使用Thread.currentThread()获取当前线程

实现Thread类

编写简单,直接this便可获得当前线程

已经继承Thread,故无法继承其它父类


线程生命周期

New

——》新建状态,java虚拟机分配内存,初始化成员变量——》

Start

——》就绪状态,虚拟机为齐创建方法调用栈,准备就绪,等待运行——》虚拟机通过线程调度,确定执行哪个就绪态线程——》

Run

——》获得CPU,开始执行run方法的方法体——》运行状态——》

Blocked

——》当一条线称运行时,它不可能一致霸占CPU,在运行过程中需要被中断,使其它线程也有机会运行——》被中断的线程进入阻塞状态——》

Dead

——》run()方法体执行完毕,线程结束——》死亡状态

注意:

  1. 一个线程只能调用一次start()方法,启用一次,死亡后也无法再次运行,故一条线程在其生命周期里只有一次调用start的机会。

  2. 启用线程调用start ,而非run,直接调用线程类的run方法,该方法立刻执行,在返回之前,其它线程无法并行执行。类似于执行一个类的普通方法,而非执行线程执行体,所以起不到多线程高校并发执行的效果。

  3. 死亡可为run方法执行完毕,或者线程直接抛异常,还可直接调用该线程的stop()方法结束该线程;但最后一种方式容易导致死锁,通常不推荐使用。

### Java 多线程环境下的事务回滚机制 在Java多线程环境中实现事务回滚主要依赖于框架的支持以及合理的编程模式。对于Spring框架而言,在多线程环境下确保事务一致性至关重要,因为并发执行可能导致事务属性受损[^2]。 #### 使用 `@Transactional` 注解控制事务边界 为了简化开发并提高可读性,推荐使用Spring提供的`@Transactional`注解来声明服务层方法的事务行为: ```java @Service public class OrderService { @Autowired private OrderRepository orderRepo; @Transactional(rollbackFor = Exception.class) public void placeOrder(Order order) throws Exception { try { // 执行订单创建逻辑... orderRepo.save(order); // 模拟异常情况触发回滚 if (order.getPrice() < 0) throw new IllegalArgumentException("价格非法"); } catch (Exception e) { log.error("发生错误, 将会回滚", e); throw e; // 抛出异常以激活回滚机制 } } } ``` 上述代码片段展示了如何利用`@Transactional`指定哪些类型的异常应该导致事务自动回滚。这里配置了任何继承自`Exception`类别的未捕获异常都会引起整个操作被撤销[^5]。 #### 结合 `PlatformTransactionManager` 进行手动管理 除了依靠注解外,还可以借助`PlatformTransactionManager`接口及其子类来进行更细粒度的手动控制。这允许开发者显式地获取、提交或回滚事务状态: ```java @Autowired private PlatformTransactionManager transactionManager; @Transactional(propagation = Propagation.NOT_SUPPORTED) public void processWithManualTxControl() { DefaultTransactionDefinition def = new DefaultTransactionDefinition(); TransactionStatus status = transactionManager.getTransaction(def); try { // ... business logic ... transactionManager.commit(status); // 成功则提交 } catch (RuntimeException ex) { transactionManager.rollback(status); // 出错即回滚 throw ex; } } ``` 此方式特别适用于那些需要跨多个数据源或其他资源的操作场景下保持一致性的场合[^4]。 #### 利用 AOP 实现全局异常捕捉与统一回滚策略 面向切面编程(AOP)可以帮助建立一套通用的异常处理流程,使得即使是在异步任务或多线程调度中也能有效地实施回滚措施。下面是一个简单的AOP配置例子: ```xml <aop:config> <aop:pointcut id="serviceMethods" expression="execution(* com.example.service..*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods"/> </aop:config> <tx:advice id="txAdvice"> <tx:attributes> <!-- 对所有匹配的服务方法启用事务支持 --> <tx:method name="*" propagation="REQUIRED" rollback-for="Throwable"/> </tx:attributes> </tx:advice> ``` 这段XML定义了一个切入点用于拦截所有的服务层方法调用,并为它们附加了一条建议——每当遇到任意抛出的`Throwable`都将强制回滚当前事务[^1]。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值