java多线程一览

  • 线程概述:
    • 多线程的目的,不是提高程序的执行速度,而是提高程序的使用率(能抢到CPU的可能比较大). 因为线程是CPU调度的基本单位,所以,当一个程序的线程较多的时候就更容易抢到cpu的资源
    • 进程:
      • 运行中的程序,系统进行资源分配和调度的独立单位
      • 每个进程都有他自己的内存空间和系统资源
    • 线程:
      • 是进程中的单个顺序控制流,是一条执行路径,cpu调度的基本单位
      • 一个进程如果有多条执行路径,:多线程
      • 一个进程如果只有一条执行路径,:单线程
  • 线程生命周期:
    •  

  • java中线程概览: [ ps : 图来自郭朝:http://blog.csdn.net/smartbetter/article/details/51335165]
  • 继承Thread类 和 实现Runnable:
 1 /**
 2 *继承Thread类 和 实现Runnable:
 3 *        1.后者解决了java单继承的局限性
 4         2.后者更适合多个相同的程序代码处理同一个资源的情况,将数据与代码有效分离,体现了java面向对象的思维
 5 *
 6 *有人说:
 7 *    前者是多个线程各自执行各自的任务,
 8 *    后者是多个线程处理相同的任务
 9 *
10 *一般用后者的人居多,因为更灵活
11 */
12 
13 // 继承Thread类
14 class MyThread extends Thread{
15     private static Object shareData; // 实现数据共享
16     @Overwrite
17     public void run(){
18         System.out.println("当前线程是"+Thread.currentThread.getName());
19     }
20 }
21 // 创建线程
22 class Main{
23     public static void main(String[] args) {
24         Thread thread=new MyThread();
25         Thread thread2=new MyThread();
26         thread.start(); // 线程开启
27         thread2.start(); // 线程开启
28     }
29 }
View Code
  • 实现Runnable创建线程类:

  

 1 // 实现Runnable创建线程类
 2 class MyRunnable implements Runnable{
 3     private Object shareData; // 实现数据共享
 4     public void run(){
 5         System.out.println("当前线程是"+Thread.currentThread.getName());
 6     }
 7 }
 8 //创建线程
 9 class Main{
10     public static void main(String[] args) {
11         // 两个线程将共享shareData共享数据
12         Runnable runa=new MyRunnable();
13         Thread thread=new MyThread(runa);
14         Thread thread2=new MyThread(runa);
15         thread.start(); // 线程开启
16         thread2.start(); // 线程开启
17     }
18 }
View Code
  • 使用Callable 和 Future接口:

  

 1 /**
 2  * 该代码来源: @蛊惑Into
 3  * Callable 和 Future接口
 4  * Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。
 5  * Callable和Runnable有几点不同:
 6  * (1)Callable规定的方法是call(),而Runnable规定的方法是run().
 7  * (2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
 8  * (3)call()方法可抛出异常,而run()方法是不能抛出异常的。
 9  * (4)运行Callable任务可拿到一个Future对象,
10  * Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。
11  * 通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果。
12  */
13 public class CallableAndFuture {
14 
15     public static class  MyCallable  implements Callable{
16           private int flag = 0; 
17           public MyCallable(int flag){
18                   this.flag = flag;
19           }
20           public String call() throws Exception{
21             if (this.flag == 0){  
22                       return "flag = 0";
23             } 
24             if (this.flag == 1){   
25                 try {
26                     while (true) {
27                             System.out.println("looping.");
28                             Thread.sleep(2000);
29                     }
30                 } catch (InterruptedException e) {
31                               System.out.println("Interrupted");
32                 }
33                 return "false";
34             } else {   
35                        throw new Exception("Bad flag value!");
36             }
37         }
38     }
39 
40     public static void main(String[] args) {
41 
42        // 定义3个Callable类型的任务
43         MyCallable task1 = new MyCallable(0);
44         MyCallable task2 = new MyCallable(1);
45         MyCallable task3 = new MyCallable(2);      
46 
47        // 创建一个执行任务的服务
48        ExecutorService es = Executors.newFixedThreadPool(3);
49         try {
50            // 提交并执行任务,任务启动时返回了一个Future对象,
51 
52             // 如果想得到任务执行的结果或者是异常可对这个Future对象进行操作
53             Future future1 = es.submit(task1);
54            // 获得第一个任务的结果,如果调用get方法,当前线程会等待任务执行完毕后才往下执行
55             System.out.println("task1: " + future1.get());
56         
57 
58             Future future2 = es.submit(task2);
59            // 等待5秒后,再停止第二个任务。因为第二个任务进行的是无限循环
60             Thread.sleep(5000);
61             System.out.println("task2 cancel: " + future2.cancel(true));
62 
63             
64            // 获取第三个任务的输出,因为执行第三个任务会引起异常
65             // 所以下面的语句将引起异常的抛出
66             Future future3 = es.submit(task3);
67             System.out.println("task3: " + future3.get());
68         } catch (Exception e){
69             System.out.println(e.toString());
70         }
71 
72        // 停止任务执行服务
73         es.shutdownNow();
74 
75     }
76 
77 }
View Code

 

  • 线程控制:

  

 1 // 线程控制
 2 
 3 join()线程---必须等线程th执行完成后才能继续向下执行
 4 ...
 5 th.start();
 6 th.join();
 7 ... 
 8 
 9 yield()礼让---注意和线程通信中wait()区分,yield将线程放到就绪队列,而wait将其放到阻塞队列
10 ...th.doSomething...
11 th.yield();
12 ...th.doSomethingElse...
13 
14 sleep()睡眠---线程睡眠,将进入阻塞队列
15 ...doSomething...
16 Thread.sleep(1000);
17 ...continueDoSomething...
18 
19 setDaemon()后台线程---将线程设置为后台线程,将在前台线程都死亡后自动死亡
20 ....
21 th.setDaemon(true);
22 ....
23 
24 setPrority()优先级---设置优先级
25 ...
26 th.setPrority(5);
27 th.start();
28 ...
View Code
  • 线程同步的3种实现:

  

  1 /* 线程同步的3种实现:
  2 *    1.同步代码块:锁对象可以是任意对象
  3                     synchronized(obj){同步代码块}
  4 *    2.同步方法:
  5             2.1 普通同步方法,锁对象是this
  6                     public synchronized void fun(){...}
  7             2.2 静态同步方法,锁对象是.class字节码对象
  8                     public static synchronized void fun(){...}
  9     3.同步锁:javaAPI提供了多种锁,如读写锁等,以及一些工具类的锁(同时具有同步和通讯特点)
 10             private Lock lock=new ReentrantLock();
 11             ...
 12             lock.lock();
 13             ...doSomething...
 14             lock.unLock();
 15 *
 16 *    
 17 *以下着重介绍几种工具类的锁使用:
 18         Samaphore
 19         CyclicBarrier
 20         CountDownLatch
 21 */
 22 /**
 23  * 线程互斥与通信:
 24  *         线程通讯之传统线程通讯: Semaphore信号灯工具
 25  *         传统的互斥,是由线程本身来控制锁的占有和释放,这就导致必须当前线程完成,或是主动让出锁,下一个线程才有机会,
 26  *         而semaphore工具, 提供相当于专门的锁的管理方全权控制索,任何线程的请求都通过管理方的许可,这样就解放了锁的控制权,让多个线程共享锁
 27  *
 28  *共有3盏灯,一次来了10个人,只用其中的3个人能够拿到等,当有灯还回的时候,等候队列的人才有机会拿到灯
 29  *可用于死锁恢复的一些场景
 30  *  
 31  * @throws Exception
 32  * @author ware E-mail:
 33  * @version create time: 20172017年3月1日下午11:35:41
 34  */
 35 public class ThreadCommunication3 {
 36     
 37     public static void main(String[] args) {
 38         final Semaphore sp=new Semaphore(3, true);
 39         
 40         ExecutorService pool = Executors.newCachedThreadPool();
 41         
 42         for (int i = 0; i < 10; i++) {
 43             Runnable task=new Runnable() {
 44                 @Override
 45                 public void run() {
 46                     try {
 47                         sp.acquire(); // 请求锁
 48                     } catch (InterruptedException e) {
 49                         e.printStackTrace();
 50                     }
 51                     System.out.println("线程"+Thread.currentThread().getName()+"已经进入---可用数"+(3-sp.availablePermits()));
 52                     
 53                     try {
 54                         Thread.sleep(1000);
 55                     } catch (InterruptedException e) {
 56                         e.printStackTrace();
 57                     }
 58                     
 59                     System.out.println("线程"+Thread.currentThread().getName()+"准备离开");
 60                     
 61                     sp.release(); //释放锁
 62                 }
 63             };
 64             
 65             pool.submit(task);
 66         }
 67         
 68     }
 69     
 70     
 71 }
 72 
 73 /**
 74  * 线程互斥与通信:
 75  *         线程通讯之传统线程通讯: CyclicBarrier工具
 76  *         所有规定的线程必须都在完成某一项工作之后才能继续下一项工作
 77  * 
 78  * 如: 班级郊游,只有所有的人都到了集合点(工作1)才能出发(工作2)
 79  *  
 80  * @throws Exception
 81  * @author ware E-mail:
 82  * @version create time: 20172017年3月1日下午11:35:41                 
 83  */
 84 public class ThreadCommunication4 {
 85     
 86     public static void main(String[] args) {
 87         final CyclicBarrier cb=new CyclicBarrier(4); // 约定有多少个人
 88         
 89         ExecutorService pool = Executors.newCachedThreadPool();
 90         
 91         for (int i = 0; i < 4; i++) {
 92             Runnable task=new Runnable() {
 93                 @Override
 94                 public void run() {
 95                     
 96                     try {
 97                         // 第一阶段工作
 98                         Thread.sleep((long) (Math.random()*1000));
 99                         System.out.println(Thread.currentThread().getName()+"到达集合点,当前共有"+cb.getNumberWaiting()+"人在等待");
100                         cb.await();
101                         
102                         // 第二阶段工作
103                         Thread.sleep((long) (Math.random()*1000));
104                         System.out.println(Thread.currentThread().getName()+"出发中"+cb.getNumberWaiting()+"人出发中");
105                         cb.await();
106                         
107                         // 第三阶段工作
108                         Thread.sleep((long) (Math.random()*1000));
109                         System.out.println(Thread.currentThread().getName()+"到达景点"+cb.getNumberWaiting()+"人到达景点");
110                         cb.await();
111                         
112                     } catch (Exception e) {
113                         e.printStackTrace();
114                     }
115                     
116                 }
117                     
118             };
119             
120             pool.submit(task);
121         }
122         
123     }
124 
125 }
126 
127 /**
128  * 线程互斥与通信:
129  *         线程通讯之传统线程通讯: CountDownLatch工具
130  *         如同一个倒计时器,当countDown()到0的时候,所有等该"计时器"的线程都会受到消息
131  * 
132  * 如: 所有的运动员都在等裁判的命令,裁判一声令下,所有的运动员收到消息开始跑,裁判等到所有的人都跑到终点了才宣布结构
133  *  
134  * @throws Exception
135  * @author ware E-mail:
136  * @version create time: 20172017年3月1日下午11:35:41                 
137  */
138 public class ThreadCommunication6 {
139     
140     public static void main(String[] args) {
141         final CountDownLatch cdOrder=new CountDownLatch(1); // 裁判命令
142         final CountDownLatch cdAnswer=new CountDownLatch(4); // 运动员的消息状态
143         
144         ExecutorService pool = Executors.newCachedThreadPool();
145         
146         // 4个运动员
147         for (int i = 0; i < 4; i++) {
148             Runnable task=new Runnable() {
149                 @Override
150                 public void run() {
151                     
152                     try {
153                         System.out.println(Thread.currentThread().getName()+"---已经准备好了,等待命令");
154                         
155                         cdOrder.await(); // 等命令
156                         
157                         System.out.println("等到命令并开跑");
158                         Thread.sleep((long) (Math.random()*1000));
159                         System.out.println(Thread.currentThread().getName()+"跑完全程了");
160                         
161                         cdAnswer.countDown();
162                         
163                     } catch (Exception e) {
164                         e.printStackTrace();
165                     }
166                     
167                 }
168                     
169             };
170             
171             pool.submit(task);
172         }
173         
174         
175         // 1个裁判
176         Runnable coach=new Runnable() {
177             @Override
178             public void run() {
179                 try {
180                     System.out.println(Thread.currentThread().getName()+"准备开炮.....碰...");
181                     cdOrder.countDown();
182                     System.out.println(Thread.currentThread().getName()+"命令已发出,等待结果...");
183                 
184                     cdAnswer.await();
185                     System.out.println(Thread.currentThread().getName()+"比赛结束,成绩出来了");
186                     
187                 } catch (InterruptedException e) {
188                     e.printStackTrace();
189                 }
190                 
191             }
192         };
193         pool.submit(coach);
194                 
195                 
196     }
197     
198     
199 }
View Code

 

  • 线程通讯:

  

  1 /* 
  2 *3种线程通讯:
  3     1. 传统线程通讯--wait(),notify();
  4     2. Condition线程通讯;
  5     2. BlockingQueue阻塞队列
  6 *
  7 */
  8 /**
  9  * 线程互斥与通信:
 10  *         线程通讯之传统线程通讯: wait(),notify(),notifyAll()(必须配合synchronized关键字)
 11  *
 12  *父线程执行10次,
 13  *子线程执行50次
 14  * @author ware E-mail:
 15  * @version create time: 20172017年3月1日下午11:35:41
 16  */
 17 public class ThreadCommunication {
 18     private static boolean isSub=false;
 19     
 20     public synchronized void doit(){
 21         while(true){
 22             while(isSub){
 23                 try {
 24                     this.wait();
 25                 } catch (InterruptedException e) {
 26                     e.printStackTrace();
 27                 }
 28             }
 29             try {
 30                 Thread.sleep(1000);
 31             } catch (InterruptedException e) {
 32                 e.printStackTrace();
 33             }
 34             for (int i = 0; i < 10; i++) {
 35                 System.out.println("main"+"----------"+i);
 36             }
 37             isSub=true;
 38             this.notify();
 39         }
 40         
 41     }
 42     public synchronized void doit2(){
 43         while(true){
 44             while(!isSub){
 45                 try {
 46                     this.wait();
 47                 } catch (InterruptedException e) {
 48                     e.printStackTrace();
 49                 }
 50             }
 51             try {
 52                 Thread.sleep(1000);
 53             } catch (InterruptedException e) {
 54                 // TODO Auto-generated catch block
 55                 e.printStackTrace();
 56             }
 57             for (int i = 0; i < 50; i++) {
 58                 System.out.println("sub"+"----------"+i);
 59             }
 60             isSub=false;
 61             this.notify();
 62         }
 63     }
 64     
 65     public static void main(String[] args) {
 66         ThreadCommunication tc=new ThreadCommunication();
 67         
 68         // 父线程    
 69         Thread fatherTh=new Thread(){
 70                 @Override
 71                 public void run() {
 72                     tc.doit();
 73                 }
 74             };
 75             
 76             // 子线程
 77         Thread sonTh=new Thread(){
 78                 @Override
 79                 public void run() {
 80                     tc.doit2();
 81                 }
 82             };
 83             
 84         fatherTh.start();
 85         sonTh.start();
 86     }
 87 }
 88 
 89 /**
 90  * 线程互斥与通信:
 91  *         线程通讯之传统线程通讯: Condition(必须配合Lock使用)
 92 
 93  * 是对阻塞队列的实现: ArrayBlockQueue
 94  * @throws Exception
 95  * @author ware E-mail:
 96  * @version create time: 20172017年3月1日下午11:35:41
 97  */
 98 public class ThreadCommunication2 {
 99     
100     private static final Lock lock=new ReentrantLock();
101     private static final Condition notFull=lock.newCondition();
102     private static final Condition notEmpty=lock.newCondition();
103     
104     private Object resources[];
105     
106     int putIndex; // 下一个可取的资源索引
107     int takeIndex; // 下一个可以存放资源的索引
108     int count; // 当前总资源数
109     
110     public ThreadCommunication2(int resourceLimit) {
111         resources=new Object[resourceLimit];
112         this.putIndex=0;
113         this.takeIndex=0;
114         this.count=0;
115     }
116     
117     public void put(Object taskResource){
118         lock.lock();
119         try {
120             while(count==resources.length){
121                 notFull.await();
122             }
123             System.out.println("-----------------put");
124             resources[putIndex]=taskResource;
125             putIndex=(putIndex%resources.length);
126             count++;
127             notEmpty.signalAll();
128         } catch (Exception e) {
129             e.printStackTrace();
130         }finally{
131             lock.unlock();
132         }
133     }
134     
135     public Object take(){
136         Object result=null;
137         lock.lock();
138         try {
139             while(count==0){
140                 notEmpty.await();
141             }
142             System.out.println("----------------take");
143             result=resources[takeIndex];
144             takeIndex=(takeIndex+1)%resources.length;
145             count--;
146             
147             notFull.signalAll();
148         } catch (Exception e) {
149             e.printStackTrace();
150         }finally{
151             lock.unlock();
152         }
153         
154         return result;
155     }
156     
157     
158     public static void main(String[] args) {
159         ThreadCommunication2 tc=new ThreadCommunication2(7); // 资源队列的长度为7
160         
161         // 开10个放线程
162         for (int i = 0; i < 10; i++) {
163             new Thread(new Runnable() {
164                 @Override
165                 public void run() {
166                     tc.put(Thread.currentThread().getName());
167                 }
168             }).start();    
169         }
170         
171         // 开10个拿线程
172         for (int i = 0; i < 10; i++) {
173             new Thread(new Runnable() {
174                 @Override
175                 public void run() {
176                     System.out.println(tc.take());
177                 }
178             }).start();
179         }
180     }
181     
182 }
183 
184 
185 /**
186 *BlockingQueue阻塞队列
187 *放线程在队列满的时候直接放弃,通知拿线程,然后进入阻塞队列,
188 *拿线程在队列空的时候直接放弃,通知放线程,然后进入阻塞队列,
189 */
190 public class DequeueTest {  
191     
192     private final static BlockingQueue<Object> queue=new ArrayBlockingQueue<>(5);
193     
194     public static void main(String[] args) throws InterruptedException {
195         
196         // 开10个放线程
197         for (int i = 0; i < 10; i++) {
198             new Thread(new Runnable() {
199                 @Override
200                 public void run() {
201                     queue.add(Thread.currentThread().getName());
202                 }
203             }).start();    
204         }
205         
206         // 开10个拿线程
207         for (int i = 0; i < 10; i++) {
208             new Thread(new Runnable() {
209                 @Override
210                 public void run() {
211                     System.out.println(queue.remove());
212                 }
213             }).start();
214         }
215         
216     }
217 
218 }
View Code
  • 线程数据共享:

  

 1 /* 线程数据共享:
 2  *        1.多个线程间共享同一个数据:
 3             1.1.多个线程的执行代码相同---多个线程共用一个Runnable的实例, 那么Runnable中的类成员将被共享;
 4  *             1.2.多个线程的执行代码不同---为多个Runnable对象传入同一个实体对象
 5  *             1.3.多个线程的执行代码不同---将多个Runnable设置为内部类,将共享实体设置为外部类成员变量
 6  *        2.一个线程的多个代码块共享一个数据:
 7  *            2.1 将 (线程,数据对象) 放到一个map中,
 8  *            2.2 一般使用java类库提供的ThreadLocal,实现原理同上,但是更优雅,而且会在线程结束后自动清理
 9  *
10  * 线程间的数据共享比较简单,这里着重介绍线程内的数据共享
11  */
12  /**
13  * 线程范围内的共享:多个模块在同一个线程中运行时要共享一份数据
14  * 
15  * 解决方式: 使用ThreadLocal---优雅版---将线程与数据分离
16  * 
17  * @param
18  * @return
19  * @throws Exception
20  * @author ware E-mail:
21  * @version create time: 20172017年3月2日上午9:07:16
22  */
23 public class ThreadScopeShared4 {
24 //    private static ThreadLocal<Integer> local=new ThreadLocal<>();
25     
26     public static void main(String[] args) {
27         for (int i = 0; i < 3; i++) {
28             new Thread(new Runnable() {
29                 @Override
30                 public void run() {
31 //                    int data=new Random().nextInt();
32 //                    local.set(data);
33                     
34                     ThreadScopeSharedData.getInstance().setAge(new Random().nextInt());
35                     ThreadScopeSharedData.getInstance().setName("vivi");
36                     new A().getNum();
37                     new B().getNum();
38                 }
39             }).start();
40         }
41         
42     }
43 
44     static class A{ // 模块A
45         public void getNum(){
46             int age=ThreadScopeSharedData.getInstance().getAge();
47             String name=ThreadScopeSharedData.getInstance().getName();
48             System.out.println(Thread.currentThread().getName()+"---------"+age);
49         }
50     }
51     static class B{ // 模块B
52         public void getNum(){
53             int age=ThreadScopeSharedData.getInstance().getAge();
54             String name=ThreadScopeSharedData.getInstance().getName();
55             System.out.println(Thread.currentThread().getName()+"---------"+age);
56         }
57     }
58 }
59 
60 // 专门与线程绑定的对象
61 class ThreadScopeSharedData{
62     private ThreadScopeSharedData() {}
63     public static ThreadScopeSharedData getInstance(){
64         ThreadScopeSharedData instance=map.get();
65         if(instance==null){
66             instance=new ThreadScopeSharedData();
67             map.set(instance);
68         }
69         return instance;
70     }
71     
72     private static ThreadLocal<ThreadScopeSharedData> map=new ThreadLocal<>();
73     
74     private int age;
75     private String name;
76     public int getAge() {
77         return age;
78     }
79     public void setAge(int age) {
80         this.age = age;
81     }
82     public String getName() {
83         return name;
84     }
85     public void setName(String name) {
86         this.name = name;
87     }
88     
89     
90 }
View Code
  •  线程池:
    • 详细:http://www.cnblogs.com/murthy/p/6495340.html

转载于:https://www.cnblogs.com/murthy/p/6509433.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/269886.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人工智能:PyTorch深度学习框架介绍

目录 1、PyTorch 2、PyTorch常用的工具包 3、PyTorch特点 4、PyTorch不足之处 今天给大家讲解一下PyTorch深度学习框架的一些基础知识&#xff0c;希望对大家理解PyTorch有一定的帮助&#xff01; 1、PyTorch PyTorch是一个基于Torch的Python机器学习框架。它是由Facebook的人工…

Linux下安装配置MySQL

一、删除原来的MySQL 在安装前要先确定系统是否已经安装了其他版本的MySQL&#xff0c;如已安装其他版本的MySQL&#xff0c;需先删除后再安装新版本。 1. 执行yum命令&#xff0c;删除MySQL的lib库&#xff0c;服务文件 yum remove mysql mysql-server mysql-libs mysql-serve…

WebSocket 是什么原理?为什么可以实现持久连接?什么情况使用WebSocket

作者&#xff1a;Ovear链接&#xff1a;https://www.zhihu.com/question/20215561/answer/40316953来源&#xff1a;知乎著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。额。。最高票答案没答到点子上&#xff0c;最后怎么跑到Nodejs上去了。…

【Swift学习笔记-《PRODUCT》读书记录-实现自定义转场动画】

iOS默认的push动画是把即将展示的控制器从右边推过来。有时我们想实现类似PPT中的一些动画&#xff0c;这时候就需要自定义转场动画了。如下图我们想实现一个淡出并且放大的过场动画&#xff0c;在退出时是一个淡出缩小的动画。 首先需要自定义一个类DiaryAnimator.swift遵守 U…

【JZOJ3598】【CQOI2014】数三角形

Mission 对于100%的数据1<m,n<1000 Solution 鬼题&#xff0c;ansC3(n∗m)−Ans&#xff0c;其中Ans表示三点共线的数目&#xff1b; 枚举最长边的向量(x,y)&#xff0c;容易算出贡献及个数。 Code #include<iostream> #include<stdio.h> #include<algor…

NSTimer定时器进阶——详细介绍,循环引用分析与解决

引言 定时器&#xff1a;A timer waits until a certain time interval has elapsed and then fires, sending a specified message to a target object. 翻译如下&#xff1a;在固定的时间间隔被触发&#xff0c;然后给指定目标发送消息。总结为三要素吧&#xff1a;时间间隔、…

HTML - 超文本标记语言 (Hyper Text Markup Language)

HTML - 超文本标记语言 (Hyper Text Markup Language) HTML是建设网站/网页制作主要语言。 HTML是一种易于学习的标记语言。 HTML使用像 <p> 尖括号内标记标签来定义网页的内容&#xff1a; HTML 实例 <html><body><h1>My First Heading</h1><…

AOP切入同类调用方法不起作用,AopContext.currentProxy()帮你解决这个坑

原来在springAOP的用法中&#xff0c;只有代理的类才会被切入&#xff0c;我们在controller层调用service的方法的时候&#xff0c;是可以被切入的&#xff0c;但是如果我们在service层 A方法中&#xff0c;调用B方法&#xff0c;切点切的是B方法&#xff0c;那么这时候是不会切…

AopContext.currentProxy();为什么能获取到代理对象

在同一个类中&#xff0c;非事务方法A调用事务方法B&#xff0c;事务失效&#xff0c;得采用AopContext.currentProxy().xx()来进行调用&#xff0c;事务才能生效。 B方法被A调用&#xff0c;对B方法的切入失效&#xff0c;但加上AopContext.currentProxy()创建了代理类&#x…

@Async注解导致循环依赖,BeanCurrentlyInCreationException异常

使用Async异步注解导致该Bean在循环依赖时启动报BeanCurrentlyInCreationException异常的根本原因分析&#xff0c;以及提供解决方案 今天在自己项目中使用Async的时候&#xff0c;碰到了一个问题&#xff1a;Spring循环依赖&#xff08;circular reference&#xff09;问题。 …

人工智能:图像数字化相关的知识介绍

❤️作者主页&#xff1a;IT技术分享社区 ❤️作者简介&#xff1a;大家好,我是IT技术分享社区的博主&#xff0c;从事C#、Java开发九年&#xff0c;对数据库、C#、Java、前端、运维、电脑技巧等经验丰富。 ❤️个人荣誉&#xff1a; 数据库领域优质创作者&#x1f3c6;&#x…

《深入理解Java虚拟机》读书笔记

堆分配参数&#xff1a; -XX:PrintGC 使用该参数&#xff0c;虚拟机启动后&#xff0c;只要遇到GC就会打印日志&#xff1b; -XX&#xff1a;UseSerialGC 配置串行回收器&#xff1b; -XX&#xff1a;PrintGCDeltails 可以查看详细信息&#xff0c;包括各个区的情况 -Xms&#…