高并发程序设计(3)—— 线程操作进阶篇

本贴最后更新于 2848 天前,其中的信息可能已经时移世改

volatile(易变的)与Java内存模型(JMM)

  • Java内存模型都是围绕原子性、有序性、可见性展开的
  • volatile:可以保证数据操作的原子性,保证操作结束,才能被读取,告诉Java虚拟机,被修饰的变量可能被别的线程修改。
    • 可以解决long类型数据在32位操作系统上并发循环赋值读取时,读取数据错误的问题。
    • 但是不能解决并发下不同的线程读取到共享资源同样的结果问题,比如多个线程对int i =0 ; i++ ,加到10000为止,最终结果会小于10000,加上volatile也如此。
    • 不能替代锁,不能保证并发下,共享资源的复合操作的原子性。

线程组

  • ThreadGroup:线程组
    • activeCount():获得活动线程的总数,但是线程是动态的,因此是个预估值,不准确
    • stop():和线程的stop()一样,不建议使用。
    • list():打印线程组内所有线程信息,对调试有帮助。

守护线程(Daemon)

  • 垃圾回收线程,JIT线程就是守护线程,与之对应的就是用户线程,用户线程可以理解为系统工作线程,它会完成这个程序应该要完成的业务操作。如果用户线程都结束了,以为只程序也无事可做了,守护线程要守护的对象已经不在,那么整个应用就自然要结束了,在一个Java应用内,当只有守护线程时Java虚拟机就会自然退出。
  • setDaemon(true):注意要在start(),之前设置,不然会抛线程状态异常,然后继续以用户线程执行。设置不生效。

线程优先级

  • setPriority(): 1-10数字越大优先级越高,但建议在应用层解决线程调度问题,优先级是个概率问题,和底层操作系统相关,并不严格保证执行机会。

线程安全和synchronized

  • 线程安全是并行程序的根本和根基,volatile并不能抱枕线程安全,只能抱枕一个线程修改了数据后,其他线程能看到改动,但当两个线程同时去修改时,有可能读到同样的值。
    • 必须保证多个线程对数据操作时完全同步,A在写入时,B不能写,也不能读。
  • synchronized: 保证多个线程对数据操作时完全同步,A在写入时,B不能写,也不能读,被限制的多个线程是串行的。
    • 指定对象:进入同步代码前,要获得对象的锁。
    • 指定方法:等同于指定对象,要先获得对象实例的锁。
    • 指定静态方法:相当于给类加锁,当操作的是static数据时,static synchronized 方法,如果不加static锁就加对象上了,获取的是对象锁,还是会并发。
    • 不要给常量加同步,如 int  integer 等,他们的赋值是一个新的引用,同步还作用在原来的引用上。

无提示的错误

  • 如int数字的加减乘除运算,如果值超出了4个字节的范围,结果就会错误,这就是溢出问题,但是并没有错误日志。在并行程序中非常容易产生错误结果。

线程调试工具

  • jstack:jps命令显示当前系统所有的java进程 , jstack打印指定进程的内部线程及堆栈。

 

 

  • 线程
    122 引用 • 111 回帖 • 3 关注
  • 并发
    75 引用 • 73 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...