多线程_2_线程生命周期

文章详细阐述了Java线程的生命周期,包括新建、就绪、执行、阻塞和死亡五个阶段。讨论了如何通过控制属性值和使用`interrupt()`方法终止线程。接着,介绍了线程同步的机制,如同步代码块、同步方法以及`join()`,`sleep()`,`wait()`等方法的使用,并提到了它们与`interrupt()`的关系。文章还涉及了线程死锁的概念和避免策略。最后,简要提及了多线程的加载方式。
摘要由CSDN通过智能技术生成

目录

1:线程的生命周期

1:线程的终止

1:通过给定属性,然后通过控制属性值来破坏继续执行的条件

2:interrupt()进行打断线程

3:含有join,sleep,wait等需要interrupt()打断

2:线程的同步(synchronized)

1:同步代码块

2:同步方法

3:线程阻塞(sleep,join,wait,notify,yield)

1:join()使用案例

4:线程死锁(max)

2:多线程加载方式

 3:总结

线程生命周期图:

含有join,sleep,wait等需要interrupt()打断

4、建议采纳


1:线程的生命周期

  1. 新建(通过构造)

  2. 就绪(通过start()方法)

  3. 执行(通过资源调度,获取资源)

  4. 阻塞

  5. 死亡

1:线程的终止

1:通过给定属性,然后通过控制属性值来破坏继续执行的条件

第一种,通过给定属性,然后通过控制属性值来破坏继续执行的条件

线程代码如下:

package cn.sz.gl.test03;

public class MyRun implements Runnable {

	private boolean flag = true;

	@Override
	public void run() {
		int i = 0;
		while (flag) {
			System.out.println("执行线程_" + i);
			i++;
		}
	}

	public void changeFlag() {
		flag = false;
	}
}

测试代码如下:

package cn.sz.gl.test03;

public class Test {

	public static void main(String[] args) {
		MyRun mr = new MyRun();
		new Thread(mr).start();
		
		
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		mr.changeFlag();
	}
}

2:interrupt()进行打断线程

第二种,对于正在执行的线程,interrupt()是给线程设置中断标志;interrupted()是检测中断并清除中断状态;isInterrupted()只检测中断。还有重要的⼀点就是interrupted()作⽤于当前线程,interrupt()和isInterrupted()作⽤于此线程,即代码中调⽤此⽅法的线程

线程代码如下:

package cn.sz.gl.test03;

public class MyRun2 implements Runnable {

	@Override
	public void run() {
		int i = 0;
		
		while(!Thread.interrupted()){
			System.out.println("我的线程_"+i);
			i++;
		}
		
	}

}

测试代码如下:

package cn.sz.gl.test03;

public class Test2 {

	public static void main(String[] args) {
		//System.out.println(Thread.interrupted());//默认为false
		
		MyRun2 mr = new MyRun2();
		Thread th = new Thread(mr);
		th.start();
		
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		th.interrupt();
		
	}
}

3:含有join,sleep,wait等需要interrupt()打断

第三种,如果线程因为执行join(),sleep()或是wait()而进入了阻塞状态,此时要想停止它,可以让它调用interrupt(),程序会抛出InterruptedException异常而被catch()子句捕获,进行处理

线程代码如下:

package cn.sz.gl.test03;

public class MyRun3 implements Runnable {

	@Override
	public void run() {
		int i = 0;
		while(true){
			System.out.println("线程_"+i);
			i++;
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				break;
			}
		}
	}

}

测试代码如下:

package cn.sz.gl.test03;

public class Test3 {

	public static void main(String[] args) {
		MyRun3 mr = new MyRun3();
		Thread th = new Thread(mr);
		th.start();
		
		
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		//当调用interrupt方法时,可以改变interrupted的值
		//当th线程中有处理InterruptedException异常的时候,如果该线程调用了interrupt方法,那么该线程会抛出InterruptedException异常
		th.interrupt();
	}
}

2:线程的同步(synchronized)

处理多线程的问题时,多个线程访问同一个对象,并且某些线程还想修改这个对象,这个时候我们就需要线程同步,线程同步其实就是一种等待机制,多个需要同时访问该对象的线程进入这个对象的等待池中,形成队列,等待前面线程使用完成,下一个线程再使用

在Java语言中,引入对象互斥锁的概念,保证共享数据操作的完整性;

每个对象都对应于一个可称为"互斥锁"的标记,这个标记保证在任一时刻,只能有一个线程访问对象;

用关键字synchronized给对象加互斥锁.

1:同步代码块

synchronized放在对象前面限制一段代码的执行,其语法如下:

Object obj = new Object();
...
synchronized(this){//this被加锁,任何其他要锁this的方法和代码块被阻塞.
 需要同步的代码;
}
...
synchronized(obj){//obj被加锁,任何其他要锁obj的代码块被阻塞.
 需要同步的代码;
}

2:同步方法

同步非静态方法:synchronized放在方法声明中,表示整个方法为同步方法,锁定this对象,如果有一个线程进入了该方法,其他线程要想使用当前this对象的任何同步方法,都必须等待前一个线程执行完该同步方法之后

如下:

public synchronized void method1(){
 …
}
public synchronized void method2(){
 …
}
public synchronized void method3(){
 …
}

同步static方法: synchronized放在static方法声明中,表示锁定该类的class对象(xxx.class,是Class类型的,是描述一个类的信息的对象)

如果有一个线程进入了该方法,其他线程要想使用当前类中的任何同步静态方法,都必须等待前一个线程执行完该同步方法之后;其他非同步方法及非静态的同步方法的执行不受影响

如下:

public synchronized static void method1(){
 …
}
public synchronized static void method2(){
 …
}

注意:

当前线程调用本同步方法时,其他线程是不允许调用本对象中其他同步方法

当前线程在调用本同步静态方法时,其他线程是不能够调用本类中的其他同步静态方法的,但是可以调用本类中的其他非同步方法或者非静态同步方法

对于同步静态方法,此时锁定的是对应的类型(类名.class),所有属于该类型的对象,都在其锁定范围内,此时可以实现方法的同步调用

线程同步的引发的问题:

  • 一个线程持有锁会导致其他所有需要该锁的线程阻塞

  • 在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题

  • 线程同步可能会造成死锁

3:线程阻塞(sleep,join,wait,notify,yield)

  1. 同步阻塞

  2. 调用sleep(),join()方法的时候,sleep()转为休眠,时间到自动唤醒

  3. wait(),notify()方法配套,转为等待,同时释放资源,通过notify()方法唤醒

  1. yield(),释放资源,与其他线程重新抢占资源,抢到就执行

  2. suspend()和resume(),由jdk1.0提供,jdk1.2之后就被放弃了,它也是让线程暂停,但是它不释放资源,导致死锁出现

1:join()使用案例

package ThreadPractise;

import java.util.ArrayList;

public class Demo implements Runnable{
    public static void parseLog(String log) throws Exception {

        System.out.println(log+":"+Thread.currentThread().getName());
        Thread.sleep(1000);
    }

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

        long start = System.currentTimeMillis();
        ArrayList<Thread> threads = new ArrayList<>();
        Demo demo = new Demo();
        Thread  t1 = new Thread(demo,"s1");
        Thread  t2 = new Thread(demo,"s2");
        Thread  t3 = new Thread(demo,"s3");
        Thread  t4 = new Thread(demo,"s4");
        threads.add(t1);
        threads.add(t2);
        threads.add(t3);
        threads.add(t4);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        for (Thread thread :
                threads) {
            thread.join();
        }
        long end = System.currentTimeMillis();
        System.out.println((end-start)/1000);
    }

    @Override
    public void run() {
        for (int i = 0; i < 4; i++) {
            try {
                parseLog(">>>"+(i+1));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

4:线程死锁(max)

死锁产生的必要条件:

1> 互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用

2> 不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。

3> 请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占用。

4> 循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路

在我们的项目中,我们不希望看到死锁的发生,为了避免,以上四个条件,破坏其中任意一个,死锁就结束了

注意:过多的同步会导致死锁

死锁示例如下:

package cn.sz.gl.no5;

public class MyRun implements Runnable {

	private static Object a = new Object();
	private static Object b = new Object();
	
	private boolean flag = true;
	
	public void changeFlag(){
		flag = false;
	}
	
	@Override
	public void run() {
		if(flag){
			synchronized (a) {
				System.out.println(Thread.currentThread().getName()+"锁定了资源a");
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (b) {
					System.out.println(Thread.currentThread().getName()+"锁定资源b");
				}
			}
		}else{
			synchronized (b) {
				System.out.println(Thread.currentThread().getName()+"锁定了资源b");
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (a) {
					System.out.println(Thread.currentThread().getName()+"锁定资源a");
				}
			}
		}
	}

}

测试如下:

package cn.sz.gl.no5;

public class Test {

	public static void main(String[] args) throws InterruptedException {
		MyRun mra = new MyRun();
		new Thread(mra,"线程1").start();
		Thread.sleep(10);
		mra.changeFlag();
		new Thread(mra,"线程2").start();
		
	}
}

2:多线程加载方式

 3:总结

线程生命周期图:

 五大状态:创建状态、就绪状态、运行状态、阻塞状态、死亡状态

含有join,sleep,wait等需要interrupt()打断

4、建议采纳

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值