线程(二)

线程的状态

  1. 新建:刚刚new出来的线程对象,还没start()
  2. 就绪:已调用start,但尚未运行,但正在积极竞争cpu
  3. 运行:正在运行
  4. 阻塞:不竞争cpu(即使cpu空闲),阻塞状态结束进入就绪状态
  5. 死亡:线程运行结束

线程的优先级

多个就绪态的线程,其中优先级较高的,竞争上cpu的概率较高。
优先级:1~10
默认5

Thread.MAX_PRIORITY  = 10
Thread.MIN_PRIORITY = 1
Thread.NORM_PRIORITY = 5

守护线程

是为其他线程提供服务的线程,守护线程随着其它非守护线程结束而自然结束的线程。
(随JVM结束)

Thread thread_0 = new Thread(()->{
	for(int i=0;;i++)//不写判断条件是因为他会随着非守护线程结束而结束。写了判断条件也只是在这个条件下结束了,不代表着这个守护线程结束。
	System.out.println("这是一个守护线程");
});
thread0.setDaemon(true);//默认为false-->非守护线程。xxx--->线程名

线程安全问题

线程同步机制---->线程一个一个进行,不能并发。

拓展:
异步编程模型:

  • 线程与线程各自执行各自的,实际上就是多线程并发
    同步编程模型:
  • 线程1在执行的时候线程2得等线程一结束,效率较低,线程排队执行。

方法
1.lock锁
2.使用线程安全的类
3.synchronized锁
4.volatile

synchronized的使用方式:

  • 同步代码块,() 里的对象就是锁
  • 同步实例方法(在实例方法上加synchronized)(等同于以this为锁,以整个方法体为同步代码块)
  • 同步静态方法(在静态方法上加synchronized)(等同于以所属类的元类对象为锁,以整个方法体为同步代码块)

三大变量安全问题

局部变量:栈中,永远不会有安全问题
静态变量:在方法区中,方法区只有一个,所以会有线程安全问题
实例变量:在堆中,堆只有一个,所以会有线程安全问题’‘

实际开发解决线程安全问题

1.局部变量 代替 实例变量和静态变量
2.在不能使用局部变量的情况下,尝试建立多个对象,使线程的对象不共享
3.加锁,尽量不适用Synchronized锁,因为该锁效率低。

实现定时器

SpringTask就是java.util.Timer为基础的

class longTimerTask extends TimerTask {
    //编写执行任务
    @Override
    public void run() {
        System.out.println("执行的任务");
    }
}
//使用定时器指定定时任务
public class TimerTaskExa {
    public static void main(String[] args) throws ParseException, ParseException {
    
        Timer timer = new Timer();//创建定时器对象
        //Timer timer2 = new Timer(true);//守护线程的方式

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date firstData = simpleDateFormat.parse("2023-5-15 18:00:00");
        
        //第一个参数:要执行的定时器代码 第二个参数:第一次执行的时间 第三个参数:每隔多长时间执行
        timer.schedule(new longTimerTask(),firstData,1000*10);
    }
}

死锁

public class 死锁 {
    private static Object object1=new Object();//锁1
    private static Object object2=new Object();//锁2
    
    public static void main(String[] args) {
    
        Thread thread1 = new Thread(()->{
            System.out.println("等object1,等object2");
            synchronized (object1){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("object1,等object2");
                synchronized (object2){
                    System.out.println("object1,object2");
                }
            }
        });
        
        Thread thread2 = new Thread(()->{
            System.out.println("等object2,等object1");
            synchronized (object2){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("object2,等object1");
                synchronized (object1){
                    System.out.println("object2,object1");
                }
            }
        });
        
        thread1.start();
        thread2.start();
    }
}

死锁的四个必要条件

  • 互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待

  • 请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放

  • 不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)

  • 循环等待条件: 若干进程间形成首尾相接循环等待资源的关系

这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

怎样避免死锁

1.加锁顺序一致
2.加锁超时时间
即线程请求资源有时间限制,一旦超出时间,就不请求了,而且释放自己的锁

ThreadLocal

ThreadLocal线程变量,其中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

public class 线程本地变量 {

    private static ThreadLocal local = new ThreadLocal();
    
    public static void f1(String str){
        local.set(str);
    }
    public static void f2(){
        System.out.println(Thread.currentThread().getName()+"..."+local.get());
    }
    //sleep的目的是为了验证在local里只会存和得到自己线程的有关信息
    public static void main(String[] args) {
        Thread thread1 = new Thread(()->{
            f1("thread1");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            f2();
        });
        Thread thread2 = new Thread(()->{
            f1("thread2");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            f2();
        });
        
        thread1.start();
        thread2.start();
    }
}
//output:
//Thread-0...thread1
//Thread-1...thread2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值