被synchronized阻塞的线程处于什么状态,java线程同步synchronized

  被synchronized阻塞的线程处于什么状态,java线程同步synchronized

  00-1010 Java中的线程状态线程安全案例分析多线程对同一个变量的写入内存可见性问题指令重排序问题同步用法同步函数本质修改常用方法修改静态方法修改代码块凝聚

  00-1010在操作系统级别,一个线程有两种状态,就绪和阻塞。

  但是在java中,为了更快的知道一个线程阻塞的原因,阻塞状态被细化。

  NEW:线程对象已创建,但系统级线程尚未创建,或者线程对象未调用start () Terminated。系统中的线程已经被销毁了,但是代码中的线程对象还在,也就是run()完成了,线程对象还在就绪队列中的RUNNABLE:线程中。随时都有可能被cpu调度执行TIMED _ WAITING:在线程执行期间,线程对象调用sleep(),它被阻塞。到了睡眠时间,它会返回到阻塞的就绪队列:一个线程锁定(同步)一个对象后,另一个线程也想锁定这个对象,就会陷入阻塞状态。只有当第一个线程解锁锁对象时,后一个线程才能锁定它。WAITING:与同步等待()一起使用。一旦一个线程调用wait(),它将首先解锁对象,并等待另一个线程通知(),然后等待中的线程才会被唤醒。当然,也可以在wait()中设置一个最大等待时间来防止这种情况发生。

  

目录

 

  00-1010概念3360什么时候一串代码叫有线安全问题?首先,线程安全问题的恶源是多线程并发执行时,会出现抢占式执行。在这里,抢先执行执行机器指令!那串代码什么时候叫有线安全问题?多线程并发时,无论几个线程如何抢占执行自己的代码,都不会影响最终的结果,这就是所谓的线程安全。但是由于抢先执行,出现了和预期不一样的结果,叫做线程安全问题,出现了bug!典型案例:使用两个线程自动递增10w乘以:公共类demo 1 { private static int count=0;public static void main(String[]args){ Thread t1=new Thread(()-{ for(int I=0;i50000i ){计数;} });t1 . start();线程t2=新线程(()-{ T2 . start();尝试{ t1 . join();T2 . join();} catch(interrupted exception e){ e . printstacktrace();} system . out . println(count);} }//打印结果:68994显然,预期的结果是10w,但是计算出来的结果却是6w多,这就说明存在线程安全问题。

  分析原因:

  只有每个线程的堆计数会增加。3360首先要明白,机器指令递增一次有三个步骤。3360.将计数值从主存储器取至cpu寄存器-将寄存器中的计数值加1-将寄存器中的计数值刷新至主存储器。我们姑且称这三个步骤为3360加载-添加-保存。

  让我们假设在一个cpu上同时执行两组指令(为了便于表示,示出了两个CPU)(不会有同时加载)3360。

  如上图中的案例:

  发现:的两个线程都执行了count一次,但是两次的结果都不理想,相当于只有一次自增。以上是一个线程安全问题。

  而且我们可以预测上面代码的结果范围从:5W到10W!为什么?

  上面两张图显示的是线程安全问题的情况,性能的结果是两个线程添加使用一次。如果两个线程一直处于这种状态(最差状态),那不就是算出来的结果是5w吗?那么,如果两个线程总是由一个线程完成加载-添加-保存,然后另一个线程再次执行这个操作,那么就会串行执行,但会是10w。

  3.以上案例如何解决?

  案例最后还提到,只要能实现串行执行,就能保证结果的正确性。那么java确实有这样一个函数供我们使用,就是synchronized关键字。

  使用.

  

 

  也就是说:cpu1执行load之前先给锁对象进行加锁,save之后再进行解锁,cpu2此时才能去给那个对象进行上锁,并进行一系列的操作.此时也就是保证了load-add-save的原子性,使得这三个步骤要么就别执行,执行就一口气执行完.

  那你可能会提问,那这样和只用一个main线程去计算自增10w次有什么区别,创建多线程还有什么意义呢?

  意义很大,因为我们创建的线程很多时候不仅仅只是一个操作,光针对自增我们可以通过加锁防止出现线程安全问题,但是各线程的其他操作要是不涉及线程安全问题那就可以并发了呀,那此时不就大大提升了执行效率咯.

  4.具体如何加锁呢?

  此处先只说一种加锁方式,先把上述案例的问题给解决了再说.

  使用关键字synchronized,此处使用的是给普通方法加synchronized修饰的方法(除此之外,synchronized还可以修饰代码块和静态方法)

  

class Counter{ private int count; synchronized public void increase(){ this.count++; } public int getCount(){ return this.count; }}public class Demo2 { private static int num=50000; public static void main(String[] args) { Counter counter=new Counter();//此时对象中的count值默认就是0 Thread t1=new Thread(()->{ for (int i = 0; i < num; i++) { counter.increase(); } }); t1.start(); Thread t2=new Thread(()->{ for (int i = 0; i < num; i++) { counter.increase(); } }); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(counter.getCount()); }}//打印10W

 

  

内存可见性问题

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: