java进阶-day9

线程

  1. 进程是一个应用程序,线程是一个进程中的执行单元。
  2. 进程之间资源是不共享的,线程之间资源是共享的。
  3. 线程和线程之间堆内存和方法区内存共享,但是栈内存独立,一个线程一个栈。也就是JVM中,只有一个堆和一个方法区,但是可以有多个栈,栈和栈之间是并发独立的。main也是一个线程。
  4. 多线程共享堆内存和方法区内存。
  5. 实现线程的方式,第一种:编写一个类,直接继承java.lang.Thread,重写run方法。然后用这个类new一个分支线程对象,然后调用start()方法,这个方法的作用是启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码任务完成后,瞬间就结束了。启动成功的线程会自动调用run方法,并且run方法在栈的底部,就和主线程的main方法一样。如果不调用start()方法,等于还是在同一个栈中。
  6. 第二种:编写一个类,实现java.lang.Runnable接口,实现run方法。然后new一个Thread类,里面的参数是编写这个类的一个对象,然后就创造的一个新的线程,然后调用start()方法,启动线程,自动调用run()方法。这种方式比较常用,因为这个类还可以去继承其他的类。也可以采用匿名内部类,直接在Thread类new对象的参数中去new接口Runnable,然后大括号重写方法就可以。
  7. 线程的生命周期:新建状态,就绪状态,运行状态,阻塞状态,死亡状态。
  8. 修改线程的名字,thread.setName(“adc”);
  9. 获取线程的名字,thread.getName();有默认的线程的名字。
  10. 获取当前线程,调用的是Thread的里面的一个静态方法,直接类名.方法名的方式调用,返回的是一个进程Thread。Thread thread=Thread.currentThread();这个方法写在那个线程中,返回的就是哪个线程,可以输出该线程的名字来确认调用的是哪个线程。
  11. Thread中有一个sleep静态方法,参数是毫秒,作用是让当前进程进去休眠进入阻塞状态,放弃占有的cpu时间片,让给其他线程使用。可以让某个线程多久执行一次。sleep是一个静态方法,就算用某个线程去调用这个方法,而调用这个方法的位置不在当前线程中,也不会让线程进入休眠状态,只有在当前线程中调用这个静态方法才会让线程进入休眠。
  12. run当中的异常不能throws,只能try,catch。因为run方法在父类中没有抛出任何异常,子类不能比父类抛出更多的异常。
  13. 如果想让一个睡眠的线程突然醒过来,需要在该线程中调用interrupt()方法,这种方法靠的是异常处理机制的方式,会让那个sleep方法异常,从而执行catch中的内容,导致trycatch结束,执行下一行代码。
  14. 正确的让线程中断是靠一个条件,修改后则停止。

多线程并发环境下数据的安全

  1. 编写的程序需要放到一个多线程环境下运行,所以更需要关注的是这些数据在多线程并发环境下是否是安全的。
  2. 当多线程并发,并且共用一个数据,而且共享的数据有修改的行为。
  3. 所以要想解决这个问题,就是当多个线程并发共享一个数据的时候,线程必须排队执行,不能并发。这种机制被叫做线程同步机制。
  4. 异步编程模型:线程t1和线程t2各自执行各自的,谁也不需要等谁,也就是多线程并发。
  5. 同步编程模型:线程t1和线程t2,t1想要执行必须等待t2线程执行结束后才能执行。
  6. 线程同步代码块,把需要线程进行同步执行的那几行代码放到synchronized(){ }的大括号中,小括号传的参数是多线程共享的数据,才能达到多线程排队。比如说有t1,t2,t3,t4四个线程,我只希望前三个线程能够排队,而后一个线程不需要排队,则这个小括号里面的就是那三个线程共享的那个对象。只要是任何共享对象的都可以。一个普通的字符串也可以,因为它在字符串常量池中,也是共享的对象。
  7. 当我们的线程遇到synchronized关键字,就会进入到锁池,lockpool。而且会放弃已经拥有的时间片,在锁池里面找对象锁,如果此时有其他线程正在使用这把锁,则这个线程就在锁池中等待,等上一个线程执行完成,把对象锁归还,这个线程找到对象锁之后,它会立即进入就绪状态,继续抢夺cpu时间片。
  8. 局部变量永远都不会存在线程安全问题。局部变量在栈中,永远不共享,一个线程就有一个栈。
  9. 实例变量在堆中。对象锁,可以创建多个对象。
  10. 静态变量在方法区中。类锁,锁住整个类。
  11. 同步代码块中的内容越少效率越高。
  12. synchronizd也可以卸载实例方法上,表示整个方法体都需要同步,但是不降执行的效率。而且共享的对象一定是this,不需要写,也不能改变。
  13. 局部变量的话建议使用StringBuilder,因为局部变量不存在线程安全问题,而StringBuffer是线程安全的,但是效率较低。
  14. 如果在静态方法中,表示的是类锁,意味着把整个类锁住了,即使new了两个新的对象,这两个对象也是同一个类,也算是共享的对象,所以会执行同步机制。

死锁

  1. 最好不要synchronized嵌套。

守护线程

  1. 线程分为:用户线程和守护线程(后台线程)。
  2. 守护线程是一个死循环,所有的用户线程结束,守护线程自动结束,main方法是一个用户线程,垃圾回收器是一个守护线程。
  3. 把一个线程设置为守护线程,只需要 在线程启动之前 thread.setDaemon(true);就会变成守护线程,即使死循环,也会在用户线程结束后自动结束。

定时器

  1. 间隔特定的时间,执行特定的程序。
  2. 每周银行账户总操作,每天进行数据的备份操作。
  3. 定时器:java.util.Timer定时器。
  4. 在实际开发中,使用多的是spring框架中提供的SpringTask框架,进行简单的配置,就可以完成定时器的任务。

实现线程的第三种方式

  1. 当某个线程执行完成之后,需要该线程返回一个值的时候,就需要用这种方法来实现线程。
  2. 实现Callable接口。
  3. get()方法可以在主线程中拿到其他线程的返回值,但是会导致主方法阻塞,直到等其他线程运行结束,主方法拿到返回值后,主方法才能接着往下运行。
  4. 首先,创建一个未来任务类对象;FuterTask task=new FuterTask();
  5. FuterTask里面构造方法的参数是一个Callbale接口实现类的对象,也可以直接匿名内部类,然后实现call方法,相当于run方法,只不过call方法返回了一个Object类的值。然后去new一个Thread对象,里面的参数就是这个FutureTask对象。

Object中的wait和notify方法

  1. 这两个方法的调用者是对象而不是线程。
  2. object.wait();表示让正在object对象上活动的线程进入等待状态,无期限等待,直到被唤醒。也就是调用object.notify();
  3. noityall()唤醒所有等待的线程。
  4. wait方法和notify方法是建立在synchronized线程同步的基础上。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力打破规则的小雄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值