您的位置:首页 > 游戏 > 手游 > 手工制作小钱包_杭州 电子商务网站建设 网络服务_东莞疫情最新消息今天新增病例_seo搜索引擎优化案例

手工制作小钱包_杭州 电子商务网站建设 网络服务_东莞疫情最新消息今天新增病例_seo搜索引擎优化案例

2024/12/28 17:12:21 来源:https://blog.csdn.net/fada_da_da/article/details/143310783  浏览:    关键词:手工制作小钱包_杭州 电子商务网站建设 网络服务_东莞疫情最新消息今天新增病例_seo搜索引擎优化案例
手工制作小钱包_杭州 电子商务网站建设 网络服务_东莞疫情最新消息今天新增病例_seo搜索引擎优化案例

线程的状态

  • 在整个线程的生命周期中,线程的状态有6种:
    • New:新建状态,新创建的线程,此时尚未调用start()方法;相当于创建Thread对象
    • Runnable:运行状态,运行中的线程,已经调用start()方法,线程正在或即将执行run()方法; 相当于开启线程
    • Terminated:终止状态,线程已终止,因此执行run()方法执行完毕。
    • Blocked:阻塞状态,运行中的线程,在等待竞争锁时,被阻塞,暂不执行。相当于线程没抢到锁进入了阻塞状态
    • Wating:等待状态,运行中的线程,因为join()等方法,进入等待;
    • Timed Wating:计时等待状态,运行中的线程,因为执行sleep(等待毫秒值)join(等待毫秒值)等方法,进入及时等待;
    • Terminated:终止状态,现成已终止,因为执行run()方法,执行完毕。

线程终止的原因有:

  • 线程正常终止:run()方法执行到return()语句返回;
  • 线程意外终止:run()方法因为未捕获的异常导致线程终止;
  • 对某个线程的Thread实例调用stop()方法强制终止(不推荐使用,因为过期) 

2.线程插队:join()方法

join()方法的作用

t.join() 方法会让当前线程进入等待池,并等待线程t执行完毕后才会被唤醒。并不影响同一时刻处在运行的其他线程。


public class Test7 {public static void main(String[] args) {//创建子线程Thread t1=new AddThread();Thread t2=new  DecThread();//启动子线程t1.start();t2.start();//线程插队try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}//查看最终结果System.out.println(Counter.count);}static class Counter{public static  int count=0;public static final  Object lock=new Object();}//递增线程static class AddThread extends Thread{public void run(){for (int i = 0; i <100000 ; i++) {synchronized (Counter.lock){Counter.count+=i;}}}}//递减线程static class DecThread extends  Thread{public void run(){for (int i=0;i<100000;i++){synchronized (Counter.lock){Counter.count-=i;}}}}
}

join() 方法的实现原理

  • join()方法的底层是利用wait()方法实现;
  • join()方法是一个synchronized同步方法,当主线程调用线程t.join()方法时,主线程获取线程t的锁,主线程进入wait()方法,等到t线程执行完成后,通过notifyALL()唤醒主线程,主线程释放锁,主线程开始继续执行。
public class Test6 {private static void printWithThread(String content){System.out.println("["+Thread.currentThread().getName()+"线程]"+content);}public static void main(String[] args) {printWithThread("开始执行main方法");//创建子线程Thread myThread=new Thread(new Runnable() {@Overridepublic void run() {printWithThread("子线程开始执行run方法");printWithThread("即将休息1秒,并让出CPU给别的线程使用");try {Thread.sleep(1000);//休眠   timed_wating   当子线程插队时间大于休眠时间,插队成功;当子线程插队时间小于休眠时间则插队失败printWithThread("我已经休息1秒,又重新获得cpu");printWithThread("休息好了,马上退出");} catch (InterruptedException e) {e.printStackTrace();}}});try {//启动子线程myThread.start();printWithThread("我在main方法里面");//主线程myThread.join(1500);//子线程插队     当子线程插队时间大于休眠时间,插队成功;当子线程插队时间小于休眠时间则插队失败printWithThread("main线程结束");} catch (InterruptedException e) {e.printStackTrace();}}
}

 join()方法和sleep()方法的区别?

  • join()实质是wait()+synchronized实现,所以join()方法结束后会释放锁;
  • sleep()不会释放锁的

线程的中断:interrupt()方法

如果线程需要执行 一个很长时间任务,就可能需要中断线程。中断线程就是其他线程给该线程发一个信号,该线程收到信号后结束执行run()方法,使得自身线程能立刻结束运行。

 interrupt()方法的作用

interrupt()方法的作用是设置该线程的中断状态为true,线程是死亡、还是等待新的任务或者是继续至下一步,就取决于中断状态。线程会不时地检测这个中断状态值,以判断线程是否应该被中断。(中断状态的值是否为true)。

interrupt()方法的原理 

作用:改变线程的中断状态为true,只有支持线程中断的方法才能用线程中断(wait、sleep、join),方法会监视线程中断状态,一旦发现状态为true,就会抛出InterruptedException异常,使方法进入终止状态。

如果线程没有被阻塞或等待,中断方法没有作用

子线程运行时,可以通过isInterrupted()方法随时观察子线程的中断状态

线程让出:yield()方法

yield()方法的作用

  • 线程通过调用yield()告诉JVM的线程调度,当前线程愿意让出CPU给其他线程使用。
  • 至于系统是否采纳,取决于JVM的线程调度模型:分时调度模型和抢占调度模型
    • 分时调度模型:所有的线程轮流获得CPU的使用权,并且平均分配每个线程占用CPU时间片;
    • 抢占式调度模式:优先让可运行池中优先级高的线程占用CPU,如果可运行池中的线程优先级相同,那么就随机选择一个线程,使其占用CPU。

子线程2执行过程中,通过yield()让出CPU,使子线程1执行概率变高。

守护线程

用户线程和守护线程的区别

  • 用户线程:就是创建的普通线程
  • 守护线程:
    1. 清除reference线程    Reference Handler
    2. 调用对象finalize方法的线程   Finalizer
    3. 分发处理给JVM信号的线程    Signal Dispatcher
    4. 添加事件监听器   Attach Listener

设置守护线程

在调用start()方法之前,调用setDaemon(true) 把该线程标记为守护线程

  • 普通用户线程,在没有完成打印内容时,JVM不会结束
  • 守护线程不会影响JVM退出
  • 用户线程的中断结束后,主线程的执行结束,会导致JVM的结束退出

多线程同步

多线程的数据不一致:当多个线程同时操作一段逻辑或代码,可能会出现数据不一致问题

多线程模式下,保证逻辑正确,对变量进行读写时,必须保证一组指令以原子方式执行:即某一个线程执行时,其他线程必须等待。

实现方式:

  1. 加锁
  2. 定义一个具有原子性的变量(AtomicInteger),调用方式实现                                      public static AtomicInteger count=new AtomicInteger(0);  该方式不用加锁

要让两个线程一次只能操作一个线程,如果加锁,必须保证两个线程加的是同一把锁 

创建一个共有的类,当作锁(Object类型的常量)

public static final Object LOCK=new Object();
synchronized (Counter.LOCK){}

当多线程调用两个不同对象同一个类时

  • 第一种锁:Counter1.class等同于this.getClass()
    synchronized (Counter1.class)等同于synchronized (this.getClass())
  • 第二种锁:静态方法上加synchronized等同于this.getClass()                               public static synchronized void toAdd()等同于synchronized (this.getClass())

当多个线程调用同一个对象时

  • 方法上加synchronized等同于synchronized(this)                                      synchronized (this)等同于public synchronized void dec()                           

 

synchronized关键字的用法

修饰普通方法:用到的锁默认为当前方法调用对象

修饰静态方法:其所用的锁,默认为Class对象

修饰代码块:其所用的锁,是指定的某个java对象

当一个线程访问对象的一个synchronized同步代码块时,另一个线程仍然可以访问该对象中的非synchronized(this)同步代码块。

父类中synchronized修饰的方法,如果子类没有重写,则该方法仍然是线程安全性;如果子类重写,并且没有使用synchronized修饰,则该方法是线程不安全的

接口方法不能使用synchronized关键字

构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步

离开synchronized代码块后,该线程锁尺有所,会自动释放

synchronized实现原理

底层原理

  使用synchronized保证线程安全,就是保证原子性,使执行过程中不会被其他线程干扰

synchronized代码块是有一对monitorenter/monitorexit指令实现,synchronized是通过对象内部监听器来实现的

每个对象有一个监听器,线程通过执行monitorenter指令尝试获取monitor的所有权,当monitor被占用时就会处于一个阻塞状态;还有一些线程会调用对象的wait(),等wait结束后,抢到的线程获得所有权,其他加入阻塞状态。 

锁升级

偏移锁、轻量级锁、重量级锁

jdk6之前,会直接加重量级锁,导致操作系统需要从用户态转为内核态,资源消耗大

jdk6之后,根据JVM检测到不同的竞争状态时,会自动切换到适合的锁实现

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com