Java多线程-synchronized关键字

来源:互联网 发布:淘宝贷款条件是什么 编辑:程序博客网 时间:2024/06/05 08:15

进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行。


一个进程中至少有一个线程

Java VM  启动的时候会有一个进程Java.exe.该进程中至少一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中。该线程称之为主线程。

扩展:其实更细节说明jvm,jvm启动不止一个线程,还有负责垃圾回收机制的线程。


那么问题来了:


一、如何在自定义的代码中,自定义一个线程呢?

通过对api的查找,java已经提供了对线程这类事物的描述,就是Thread类。

Java中建立线程的方法有俩种:


1、通过某个类继承Thread类,并且重写run()方法来实现(不推荐)

2、通过某个类实现Runnable接口,并且重写run()方法 来实现

不推荐使用第一种的原因:Java是单继承的,如果某个类extends了Thread类,将不能再继承别的类,影响了代码的延展性。

俩种方法的区别:启动方法不同。

方法1:直接   线程名.start();即可启动线程。

方法2:先new一个对象,如:Test t=new Test();   //此时线程并没有被创建。

然后建立线程对象,并且将t放入其中, Thread td1=new Thread(t);

最后通过td1.start()来启动线程。

“方法2的启动方式其实就是将实现了Runnable接口的类的对象转换成标准的Thread类对象,然后再.start()来启动”


二、如果创建俩个线程,则会发现运行结果每一次都不同。


因为多个线程都获取cpu的执行权。cpu执行到谁,谁就运行。明确一点,在某一个时刻,只能有一个程序在运行。(多核除外)cpu在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象把多线程的运行行为在互相抢夺cpu的执行权。

这就是多线程的一个特性:随机性。谁抢到谁执行,至于执行多长,cpu说的算。


三、为什么要覆盖run方法呢?

Thread类用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。也就是说Thread类中的run方法,用于存储线程要运行的代码。


java线程的同步--提出问题

      多线程的并发,给我们编程带来很多好处,完成更多更有效率的程序。但是也给我们带来线程安全问题。

多线程的运行出现了安全问题。

问题的原因:
    当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,
    另一个线程参与进来执行。导致共享数据的错误。
 

java线程的同步--解决问题


    对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。Java对于多线程的安全问题提供了专业的解决方式。

就是同步代码块。

synchronized(对象)
{
    需要被同步的代码

}

      关键就是要保证容易出问题的代码的原子性所谓原子性就是指:当a线程在执行某段代码的时候,别的线程必须等到a线程执行完后,它才能执行这段代码。也就是排队一个一个解决。

对象如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。

同步的前提:
1,必须要有两个或者两个以上的线程。
2,必须是多个线程使用同一个锁。

必须保证同步中只能有一个线程在运行。


好处:解决了多线程的安全问题。

弊端:多个线程需要判断锁,较为消耗资源,


售票案例演示

[java] view plain copy
  1. class Ticket implements Runnable  
  2. {  
  3.     private  int tick = 1000;  
  4.     Object obj = new Object();  
  5.     public void run()  
  6.     {  
  7.         while(true)  
  8.         {  
  9.             //同步锁,同步代码块  
  10.             synchronized(obj)  
  11.             {  
  12.                 if(tick>0)  
  13.                 {  
  14.                     //try{Thread.sleep(10);}catch(Exception e){}  
  15.                     System.out.println(Thread.currentThread().getName()+"....sale : "+ tick--);  
  16.                 }  
  17.             }  
  18.         }  
  19.     }  
  20. }  
  21.   
  22.   
  23. public class  TestThread  
  24. {  
  25.     public static void main(String[] args)   
  26.     {  
  27.   
  28.         Ticket t = new Ticket();  
  29.   
  30.         Thread t1 = new Thread(t);  
  31.         Thread t2 = new Thread(t);  
  32.         Thread t3 = new Thread(t);  
  33.         Thread t4 = new Thread(t);  
  34.         t1.start();  
  35.         t2.start();  
  36.         t3.start();  
  37.         t4.start();  
  38.   
  39.   
  40.     }  
  41. }  

运行结果如下:由图可知,四个线程均在正常执行,并且实现了同步。

    


同步可以是一个同步代码块,也可以对一个函数进行同步,即使用同步函数。

*******注意******* 

run()函数不可以被同步
*******注意*******

同步函数用的是哪一个锁呢?

      函数需要被对象调用。那么函数都有一个所属对象引用。就是this。所以同步函数使用的锁是this。

如果同步函数被静态修饰后,使用的锁是什么呢?      通过验证,发现不在是this。因为静态方法中也不可以定义this。静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。类名.class  该对象的类型是Class     静态的同步方法,使用的锁是该方法所在类的字节码文件对象。 类名.class

举例如下:

[java] view plain copy
  1. class Ticket implements Runnable  
  2. {  
  3.     private static  int tick = 100;  
  4.     //Object obj = new Object();  
  5.     boolean flag = true;  
  6.     public  void run()  
  7.     {  
  8.         if(flag)  
  9.         {  
  10.             while(true)  
  11.             {  
  12.                 synchronized(Ticket.class)  
  13.                 {  
  14.                     if(tick>0)  
  15.                     {  
  16.                         try{Thread.sleep(10);}catch(Exception e){}  
  17.                         System.out.println(Thread.currentThread().getName()+"....code : "+ tick--);  
  18.                     }  
  19.                 }  
  20.             }  
  21.         }  
  22.         else  
  23.             while(true)  
  24.                 show();  
  25.     }  
  26.     public static synchronized void show()  
  27.     {  
  28.         if(tick>0)  
  29.         {  
  30.             try{Thread.sleep(10);}catch(Exception e){}  
  31.             System.out.println(Thread.currentThread().getName()+"....show.... : "+ tick--);  
  32.         }  
  33.     }  
  34. }  
  35.   
  36.   
  37. public class  StaticMethodDemo  
  38. {  
  39.     public static void main(String[] args)   
  40.     {  
  41.   
  42.         Ticket t = new Ticket();  
  43.   
  44.         Thread t1 = new Thread(t);  
  45.         Thread t2 = new Thread(t);  
  46.         t1.start();  
  47.         try{Thread.sleep(10);}catch(Exception e){}  
  48.         t.flag = false;  
  49.         t2.start();  
  50.   
  51.   
  52.     }  
  53. }  

       此例子中,使用了一个同步代码块和同步函数。分别在执行,俩者必须使用同一个锁才能保证现场安全。经测试,同步代码块中使用Ticket.class可以保证安全,所以静态同步函数中使用的锁即为:该方法所在类的字节码文件对象,类名.class
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 下载ppt变成php文件怎么办 数据库bak文件损坏了怎么办? wps文档大小超出上传限制怎么办 手机百度用微盘下载不了文件怎么办 无法读取源文件或磁盘怎么办 文件中转站未安装上传控件怎么办 手机外国网址网速太差怎么办 istpng里显示不出图片怎么办 电脑上保持登录状态后怎么办 电脑打游戏闪退怎么办 实训老师教不好怎么办 善心汇损失的钱怎么办 去陌生的地方怕传销怎么办 被执行人不提供财产线索怎么办 宽带ip地址改了怎么办 移动宽带恢复出厂设置了怎么办 移动100兆网速慢怎么办 手机显示无法解析dns地址怎么办 台式电脑宽带连接不上怎么办 电信宽带账号登录密码忘记了怎么办 电信校园宽带超时了怎么办 宽带连接账号密码忘了怎么办 移动宽带路由器上不了网怎么办 移动宽带太卡了怎么办 电信adsl密码忘记了怎么办 移动宽带无法连接网络怎么办 移动宽带电视无信号怎么办 联通网线故障电话打不通怎么办 w10系统ip地址错误怎么办 移动流量太贵了怎么办 修改wifi密码ip地址怎么办 苹果6s接电话声音小怎么办 k歌录音器失败怎么办 想报警但不能说话怎么办 微粒贷要家人电话怎么办 4g网络信号差怎么办 手机移动网络信号不好怎么办 移动的4g网络差怎么办 4g移动网络慢怎么办 房间没有4g网络怎么办 oppo显示2g网络怎么办