[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 中著名的垃圾回收器就是一个守护线程,只有应用程序中所有的线程结束,它才会结束。

原文地址:https://www.cnblogs.com/jiasq/p/8528193.html