zoukankan      html  css  js  c++  java
  • [Js-Java SE]线程同步(加锁)(synchronized,守护进程,死锁,计时器)

     1 /*
     2     t1和t2
     3 
     4     异步编程模型:t1线程执行t1的,t2线程执行t2的,两个线程之间谁也不等谁。
     5 
     6     同步编程模型:t1线程和t2线程执行,当t1线程必须等t2线程执行结束之后,t1线程才能执行,这是同步编程模型。
     7 
     8 
     9     什么时候要同步呢?为什么要引入线程同步呢?
    10         1.为了数据的安全。尽管应用程序的使用率降低,但是为了保证数据是安全的,必须加入线程同步机制。
    11         线程同步机制使程序变成了(等同)单线程。
    12 
    13         2.什么条件下要使用线程同步?
    14             第一:必须是多线程环境
    15             第二:多线程环境共享同一个数据.
    16             第三:共享的数据涉及到修改操作。
    17     
    18     以下程序演示取款例子。以下程序不使用线程同步机制,多线程
    19     同时对同一个账户进行取款操作,会出现什么问题?
    20 */
    21 public class ThreadTest12
    22 {
    23     public static void main(String[] args){
    24         
    25         //创建一个公共的账户
    26         Account act = new Account("actno-001",5000.0);
    27 
    28         //创建线程对同一个账户取款
    29         Thread t1 = new Thread(new Processor(act));
    30         Thread t2 = new Thread(new Processor(act));
    31 
    32         t1.start();
    33 
    34         t2.start();
    35     }
    36 }
    37 
    38 //取款线程
    39 class Processor implements Runnable
    40 {
    41     //账户
    42     Account act;
    43 
    44     //Constructor
    45     Processor(Account act){
    46         this.act = act;
    47     }
    48 
    49     public void run(){
    50         act.withdraw(1000.0);
    51         System.out.println("取款1000.0成功,余额:" + act.getBalance());
    52     }
    53 }
    54 
    55 //账户
    56 class Account
    57 {
    58     private String actno;
    59     private double balance;
    60 
    61     public Account(){}
    62     public Account(String actno,double balance){
    63         this.actno = actno;
    64         this.balance = balance;
    65     }
    66 
    67     //setter and getter
    68     public void setActno(String actno){
    69         this.actno = actno;
    70     }
    71 
    72     public void setBalance(double balance){
    73         this.balance = balance;
    74     }
    75 
    76     public String getActno(){
    77         return actno;
    78     }
    79 
    80     public double getBalance(){
    81         return balance;
    82     }
    83 
    84     //对外提供一个取款的方法
    85     public void withdraw(double money){ //对当前账户进行取款操作
    86 
    87         double after = balance - money;
    88         
    89         //延迟
    90         try{Thread.sleep(1000);}catch(Exception e){}
    91         
    92 
    93         //更新
    94         this.setBalance(after);
    95     }
    96 }
    // 以上程序输出结果
    /*
    ---------- java ----------
    取款1000.0成功,余额:4000.0
    取款1000.0成功,余额:4000.0
    
    Output completed (1 sec consumed) - Normal Termination
    */

    由上面的结果可知在第一个线程更新余额之前,第二个线程访问了账户余额,才导致了上面的结果,利用Java的synchronized关键字,我们改进的程序如下:

     1 /*
     2     以下程序使用线程同步机制保证数据的安全。
     3 */
     4 public class ThreadTest13
     5 {
     6     public static void main(String[] args){
     7         
     8         //创建一个公共的账户
     9         Account act = new Account("actno-001",5000.0);
    10 
    11         //创建线程对同一个账户取款
    12         Thread t1 = new Thread(new Processor(act));
    13         Thread t2 = new Thread(new Processor(act));
    14 
    15         t1.start();
    16 
    17         t2.start();
    18     }
    19 }
    20 
    21 //取款线程
    22 class Processor implements Runnable
    23 {
    24     //账户
    25     Account act;
    26 
    27     //Constructor
    28     Processor(Account act){
    29         this.act = act;
    30     }
    31 
    32     public void run(){
    33         act.withdraw(1000.0);
    34         System.out.println("取款1000.0成功,余额:" + act.getBalance());
    35     }
    36 }
    37 
    38 //账户
    39 class Account
    40 {
    41     private String actno;
    42     private double balance;
    43 
    44     public Account(){}
    45     public Account(String actno,double balance){
    46         this.actno = actno;
    47         this.balance = balance;
    48     }
    49 
    50     //setter and getter
    51     public void setActno(String actno){
    52         this.actno = actno;
    53     }
    54 
    55     public void setBalance(double balance){
    56         this.balance = balance;
    57     }
    58 
    59     public String getActno(){
    60         return actno;
    61     }
    62 
    63     public double getBalance(){
    64         return balance;
    65     }
    66 
    67     //对外提供一个取款的方法
    68     public void withdraw(double money){ //对当前账户进行取款操作
    69         
    70         //把需要同步的代码,放到同步语句块中.
    71         /*
    72             原理:t1线程和t2线程.
    73             t1线程执行到此处,遇到了synchronized关键字,就会去找this的对象锁,
    74             如果找到this对象锁,则进入同步语句块中执行程序。当同步语句块中的代码
    75             执行结束之后,t1线程归还this的对象锁。
    76 
    77             在t1线程执行同步语句块的过程中,如果t2线程也过来执行以下代码,也遇到
    78             synchronized关键字,所以也去找this的对象锁,但是该对象锁被t1线程持有,
    79             只能在这等待this对象的归还。
    80         */
    81         synchronized(this){
    82 
    83             double after = balance - money;
    84         
    85             //延迟
    86             try{Thread.sleep(1000);}catch(Exception e){}
    87             
    88 
    89             //更新
    90             this.setBalance(after);
    91         }
    92         
    93     }
    94 }
    // 运行结果:
    /*
    ---------- java ----------
    取款1000.0成功,余额:4000.0
    取款1000.0成功,余额:3000.0
    
    Output completed (2 sec consumed) - Normal Termination
    */

    sychronized修饰静态代码块或者静态方法,产生类锁,每个类共享一把锁

    sychronized修饰非静态代码块或者成员方法,产生对象锁,每个对象共享一把锁

    死锁

    以下程序描述了死锁

     1 /*
     2     死锁
     3 */
     4 public class DeadLock
     5 {
     6     public static void main(String[] args){
     7 
     8         Object o1 = new Object();
     9         Object o2 = new Object();
    10 
    11         Thread t1 = new Thread(new T1(o1,o2));
    12         Thread t2 = new Thread(new T2(o1,o2));
    13 
    14         t1.start();
    15         t2.start();
    16 
    17     }
    18 }
    19 
    20 class T1 implements Runnable
    21 {
    22     Object o1;
    23     Object o2;
    24 
    25     T1(Object o1,Object o2){
    26         this.o1 = o1;
    27         this.o2 = o2;
    28     }
    29 
    30     public void run(){
    31         synchronized(o1){
    32             try{Thread.sleep(1000);}catch(Exception e){}
    33             synchronized(o2){
    34             
    35             }
    36         }
    37     }
    38 }
    39 
    40 
    41 class T2 implements Runnable
    42 {
    43     Object o1;
    44     Object o2;
    45 
    46     T2(Object o1,Object o2){
    47         this.o1 = o1;
    48         this.o2 = o2;
    49     }
    50 
    51     public void run(){
    52         synchronized(o2){
    53             try{Thread.sleep(1000);}catch(Exception e){}
    54             synchronized(o1){
    55             
    56             }
    57         }
    58     }
    59 }

    以上程序将永远等待执行,相似的概念是“羊群效应”,“哲学家吃饭问题”

    守护线程

    从线程分类上可以分为:用户线程(以上讲的都是用户线程),另一个是守护线程。守护线程是这样的,所有的用户线程结束生命周期,守护线程才会结束生命周期,只要有一个用户线程存在,那么守护线程就不会结束,例如 java 中著名的垃圾回收器就是一个守护线程,只有应用程序中所有的线程结束,它才会结束。

     1 /*
     2     守护线程.
     3 
     4     其他所有的用户线程结束,则守护线程退出!
     5     守护线程一般都是无限执行的.
     6 */
     7 public class ThreadTest19
     8 {
     9     public static void main(String[] args) throws Exception{
    10         
    11         Thread t1 = new Processor();
    12 
    13         t1.setName("t1");
    14         
    15         //将t1这个用户线程修改成守护线程.
    16         t1.setDaemon(true);
    17 
    18         t1.start();
    19         
    20         //主线程
    21         for(int i=0;i<10;i++){
    22             System.out.println(Thread.currentThread().getName()+"-->"+i);
    23             Thread.sleep(1000);
    24         }
    25     }
    26 }
    27 
    28 class Processor extends Thread
    29 {
    30     public void run(){
    31         int i = 0;
    32         while(true){
    33             
    34             i++;
    35 
    36             System.out.println(Thread.currentThread().getName()+"-->"+i);
    37 
    38             try{Thread.sleep(500);}catch(Exception e){}
    39             
    40         }
    41 
    42     }
    43 }
    // 输出结果
    /*
    ---------- java ----------
    main-->0
    t1-->1
    t1-->2
    main-->1
    t1-->3
    t1-->4
    main-->2
    t1-->5
    t1-->6
    main-->3
    t1-->7
    t1-->8
    main-->4
    t1-->9
    t1-->10
    main-->5
    t1-->11
    t1-->12
    main-->6
    t1-->13
    t1-->14
    main-->7
    t1-->15
    t1-->16
    main-->8
    t1-->17
    t1-->18
    main-->9
    t1-->19
    t1-->20
    
    Output completed (10 sec consumed) - Normal Termination
    */

    主线程输出结束之后 t 线程结束

    定时器

     1 /*
     2     关于定时器的应用.
     3     作用:每隔一段固定的时间执行一段代码.
     4 */
     5 import java.text.*;
     6 import java.util.*;
     7 
     8 public class TimerTest01
     9 {
    10     public static void main(String[] args) throws Exception{
    11         
    12         //1.创建定时器
    13         Timer t = new Timer();
    14 
    15         //2.指定定时任务
    16         t.schedule(
    17                 new LogTimerTask(), 
    18                 new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").parse("2012-08-03 17:37:00 000"), 
    19                 1000*10);
    20 
    21     }
    22 }
    23 
    24 //指定任务
    25 class LogTimerTask extends TimerTask
    26 {
    27     public void run(){
    28         System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()));
    29     }
    30 }

    注意:java.lang.Object下有两个方法分别是notify和wait,是控制当前对象线程等待和继续的方法

    从线程分类上可以分为:用户线程(以上讲的都是用户线程),另一个是守护线程。守护线栈 堆 方法区main{……..}run {………}t1 线程run{i=0..i<10}t2 线程run {i=0..i<10}Processors = 0s = 45Processors = 0s = 45动力节点 http://www.bjpowernode.com17程是这样的,所有的用户线程结束生命周期,守护线程才会结束生命周期,只要有一个用户线程存在,那么守护线程就不会结束,例如 java 中著名的垃圾回收器就是一个守护线程,只有应用程序中所有的线程结束,它才会结束。

  • 相关阅读:
    线程带参数操作
    静态页面不识别include
    当网站遭遇DDOS攻击的解决方案及展望
    带进度条上传控件
    用js实现了表格数据管理的以下几个功能:
    怎么面试一个人
    map的使用
    在Axapta中实现trim函数
    Axapta财务过账分析(一)
    在Axapta中实现split函数
  • 原文地址:https://www.cnblogs.com/jiasq/p/8528193.html
Copyright © 2011-2022 走看看