内容摘抄来自:传智播客 张孝祥 老师的《Java高新技术》视频, 并加入了个人总结和理解。
虽然我没有参加过任何培训班,但我很大一部分知识都来自于传智播客的网络分享视频。
十分真挚的感谢张老师的公开视频。
1.传统线程技术的回顾
1 import org.junit.Test; 2 /** 3 * 传统线程回顾 4 * 多线程不一定会提高运行效率,和CPU设计和架构有关。 5 * 多线程下载是抢了服务器的资源,并不是自身的机器加快。 6 * @author LiTaiQing 7 */ 8 public class TraditionThread { 9 /** 10 * 两种传统线程的创建方式 11 */ 12 @Test 13 public void test1(){ 14 //方式一 15 Thread thread = new Thread(){ 16 /** 17 * 从Thread.class源代码中发现,run方法在默认情况下是执行默认target.run(); 18 * @Override 19 public void run() { 20 if (target != null) { 21 target.run(); 22 } 23 } 24 25 private Runnable target; 26 */ 27 @Override 28 public void run() { 29 while(true){ 30 System.out.println(Thread.currentThread().getName()); 31 //不要使用this,因为在Runnable创建线程的方式中this是无效的 32 //System.out.println(this.getName()); 33 } 34 } 35 }; 36 thread.start(); 37 /** 38 * 方式二 39 * 使用Runnable更好,更加符合面向对象程序设计的思想,程序结构的耦合性更低,将任务和宿主分离 40 */ 41 Thread thread2 = new Thread(new Runnable(){ 42 @Override 43 public void run() { 44 while(true){ 45 System.out.println(Thread.currentThread().getName()); 46 //报错 47 //System.out.println(this.getName()); 48 } 49 } 50 }); 51 thread2.start(); 52 //------------------------------------- 53 /** 54 * 考虑回运行哪一块代码? 55 */ 56 new Thread(new Runnable(){ 57 @Override 58 public void run() { 59 while(true){ 60 try { 61 Thread.sleep(500); 62 } catch (InterruptedException e) { 63 e.printStackTrace(); 64 } 65 System.out.println("Runable:"+Thread.currentThread().getName()); 66 } 67 } 68 }){ 69 /** 70 * 会运行此代码块,子类覆盖了父类的方法 ,那么就先运行子类,否则就去找父类 71 */ 72 @Override 73 public void run() { 74 while(true){ 75 try { 76 Thread.sleep(500); 77 } catch (InterruptedException e) { 78 e.printStackTrace(); 79 } 80 System.out.println("Run:"+Thread.currentThread().getName()); 81 } 82 } 83 }.start(); 84 } 85 }
2.传统定时器技术回顾 - Timer类 TimerTask
java.util
类 Timer
java.lang.Object java.util.Timer
方法摘要 | |
---|---|
void |
cancel() 终止此计时器,丢弃所有当前已安排的任务。 |
int |
purge() 从此计时器的任务队列中移除所有已取消的任务。 |
void |
schedule(TimerTask task, Date time) 安排在指定的时间执行指定的任务。 |
void |
schedule(TimerTask task, Date firstTime, long period) 安排指定的任务在指定的时间开始进行重复的固定延迟执行。 |
void |
schedule(TimerTask task, long delay) 安排在指定延迟后执行指定的任务。 |
void |
schedule(TimerTask task, long delay, long period) 安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。 |
void |
scheduleAtFixedRate(TimerTask task, Date firstTime, long period) 安排指定的任务在指定的时间开始进行重复的固定速率执行。 |
void |
scheduleAtFixedRate(TimerTask task, long delay, long period) 安排指定的任务在指定的延迟后开始进行重复的固定速率执行。 |
1 import java.util.Date; 2 import java.util.Timer; 3 import java.util.TimerTask; 4 import org.junit.Test; 5 /** 6 * 传统定时器 7 * 工具 quartz 可以完成在周几执行任务的需求 8 * @author LiTaiQing 9 */ 10 public class TraditionalTimerTest { 11 /** 12 * 传统定时器的使用实例 13 */ 14 @Test 15 public void test1(){ 16 /* 17 * schedule 调度 18 * Timer是定时器 19 * TimerTask是定时器的任务 20 */ 21 new Timer().schedule(new TimerTask(){ 22 @Override 23 public void run() { 24 System.out.println("bombing!"); 25 } 26 }, 10000,3000);//第一次执行是10秒之后,以后每隔3秒执行一次 27 printSeconds(); 28 } 29 30 /** 31 * 实现刚开始2秒执行,之后4秒执行一次 32 * 代码思想从每次2秒执行一次改到目标结果 33 */ 34 //通过一个标记,判断当前任务应该多少秒后执行 35 private static int count = 0; 36 @Test 37 public void test2(){ 38 /** 39 * 内部类内部不能出现静态变量。 40 */ 41 class MyTimerTask extends TimerTask{ 42 @Override 43 public void run() { 44 count = (count + 1)%2; 45 System.out.println("bombing!"); 46 new Timer().schedule( 47 /*new TimerTask(){ 48 @Override 49 public void run() { 50 System.out.println("bombing!"); 51 } 52 }*/ 53 new MyTimerTask(), 2000+2000*count); 54 } 55 } 56 new Timer().schedule(new MyTimerTask(),2000); 57 printSeconds(); 58 } 59 60 /** 61 * “实现任务刚开始2秒执行,之后4秒执行一次”的另一种方法 62 */ 63 @Test 64 public void test3(){ 65 new Timer().schedule(new MyTimerTask2(), 2000); 66 printSeconds(); 67 } 68 class MyTimerTask1 extends TimerTask{ 69 @Override 70 public void run() { 71 System.out.println("bombing!"); 72 new Timer().schedule(new MyTimerTask2(), 2000); 73 } 74 } 75 class MyTimerTask2 extends TimerTask{ 76 @Override 77 public void run() { 78 System.out.println("bombing!"); 79 new Timer().schedule(new MyTimerTask1(), 4000); 80 } 81 } 82 83 private void printSeconds(){ 84 while(true){ 85 System.out.println(new Date().getSeconds()); 86 try { 87 Thread.sleep(1000); 88 } catch (InterruptedException e) { 89 e.printStackTrace(); 90 } 91 } 92 } 93 }
3.传统线程互斥技术
线程安全问题可以用银行转账来解释
1 /** 2 * 传统的线程互斥技术 3 * @author LiTaiQing 4 */ 5 public class TraditionalThreadSynchronized { 6 7 public static void main(String[] args){ 8 new TraditionalThreadSynchronized().init(); 9 } 10 11 private void init(){ 12 /** 13 * 内部类访问局部变量,局部变量要加final 14 * 若此代码放在main中会报错,因为静态代码块不能访问内部类 15 */ 16 final Outputer outputer = new Outputer(); 17 new Thread(new Runnable(){ 18 @Override 19 public void run() { 20 while(true){ 21 try { 22 Thread.sleep(1000); 23 } catch (InterruptedException e) { 24 e.printStackTrace(); 25 } 26 outputer.output("zhangxiaoxiang"); 27 } 28 } 29 }).start(); 30 new Thread(new Runnable(){ 31 @Override 32 public void run() { 33 while(true){ 34 try { 35 Thread.sleep(1000); 36 } catch (InterruptedException e) { 37 e.printStackTrace(); 38 } 39 outputer.output("lihuoming"); 40 } 41 } 42 }).start(); 43 } 44 45 static class Outputer{ 46 public void output(String name){ 47 int len = name.length(); 48 /* 49 * 锁用任意一个对象都行,但只有同一个对象才具有互斥性 50 * 1.每个类的字节码文件只有一份,可以用来做互斥锁 51 * 2.用this也行 52 * 此处也可以在方法上架synchroized, 53 * 但从多线程效率角度来看,合理细化同步块粒度能提高执行效率, 54 * 所以此处在内部代码中加synchroized比较好 55 */ 56 synchronized(Outputer.class){ 57 for(int i = 0; i < len ; i++){ 58 System.out.print(name.charAt(i)); 59 } 60 System.out.println(); 61 } 62 } 63 /** 64 * output2方法不会同步,因为方法上加synchronized相当于加this锁 65 * 但又是静态方法,所以this会失效,会出现问题。 66 * @param name 67 */ 68 public static synchronized void output2(String name){ 69 int len = name.length(); 70 synchronized(Outputer.class){ 71 for(int i = 0; i < len ; i++){ 72 System.out.print(name.charAt(i)); 73 } 74 System.out.println(); 75 } 76 } 77 } 78 }
4.传统线程同步通信技
1 /** 2 * 传统线程同步通信技术 3 * 4 * ******************************************* 5 * 经验: 6 * 要用到共同数据(包括共同锁)或共同算法的若干个方法应该 7 * 归在用一个类身上,这种设计正好体现了高内聚和程序的健壮性。 8 * 9 * ******************************************* 10 * 11 * @author LiTaiQing 12 */ 13 public class TraditionalThreadCommunication { 14 15 /************************************************** 16 * 调试小技巧 17 * 如果由于Console的输出太多而造成面板显示的数据不完整 18 * 可设置运行前参数设置 19 * 右键->Run As->Run Configuractions->Common->File 20 * 选择保存的路径即可 21 * 22 ************************************************** 23 */ 24 25 26 /** 27 * 面试题 28 * ·子线程循环10次,接着主线程循环100,接着又回到子线程循环10次, 29 * ·接着再回到主线程又循环100,如此循环50次,请写出程序 30 */ 31 public static void main(String[] args){ 32 33 final Business business = new Business(); 34 new Thread(new Runnable(){ 35 @Override 36 public void run() { 37 for(int i = 1; i <= 50; i++){ 38 business.sub(i); 39 } 40 } 41 }).start(); 42 for(int i = 1; i <= 50; i++){ 43 business.main(i); 44 } 45 } 46 47 } 48 49 class Business{ 50 private boolean bShouldSub = true; 51 public synchronized void sub(int i){ 52 /** 53 * 此处将if改为while,增强代码健壮性。 54 * 防止伪唤醒! 55 */ 56 while(!bShouldSub){ 57 try { 58 this.wait(); 59 } catch (InterruptedException e) { 60 e.printStackTrace(); 61 } 62 } 63 for(int j = 1; j <= 10; j++){ 64 System.out.println("sub thread sequece of " + j + ",loop of " +i); 65 } 66 bShouldSub = false; 67 this.notify(); 68 } 69 public synchronized void main(int i){ 70 while(bShouldSub){ 71 try { 72 this.wait(); 73 } catch (InterruptedException e) { 74 e.printStackTrace(); 75 } 76 } 77 for(int j = 1; j <= 100; j++){ 78 System.out.println("main thread sequece of " + j + ",loop of " +i); 79 } 80 bShouldSub = true; 81 this.notify(); 82 } 83 }
5.线程范围内共享变量的概念与作用
1 import java.util.HashMap; 2 import java.util.Map; 3 import java.util.Random; 4 5 /******************************* 6 * 模拟ThrealLocal的实现 7 * 用处: 8 * 用在数据库操作中俄beginTransaction -> commit 9 * 在Hibernate中也是使用它来保证在多线程下Session自己不冲突。 10 * OpenSessionInView模式 11 * spring的OpenSessionInView也是使用ThreadLocal来实现, OpenSessionInViewFilter过滤器 12 * 当请求到底是打开一个session,请求结束时关闭。 13 * 缺陷就是如果客户端的网速慢,会导致数据库的链接一直被占用。 14 * 扩展:OpenSessionInView模式用AOP替代 15 * ***************************** 16 * @author LiTaiQing 17 */ 18 public class ThreadScopeShareData { 19 private static Map<Thread,Integer> threadData = new HashMap<Thread,Integer>(); 20 public static void main(String[] args){ 21 for(int i = 0; i < 10 ; i++){ 22 new Thread(new Runnable(){ 23 @Override 24 public void run() { 25 int data = new Random().nextInt(); 26 System.out.println(Thread.currentThread().getName() + " get put data :" + data); 27 threadData.put(Thread.currentThread(), data); 28 new A().get(); 29 new B().get(); 30 } 31 }).start(); 32 } 33 } 34 static class A{ 35 public void get(){ 36 int data = threadData.get(Thread.currentThread()); 37 System.out.println("A from" + Thread.currentThread().getName() + " get put data :" + data); 38 } 39 } 40 static class B{ 41 public void get(){ 42 int data = threadData.get(Thread.currentThread()); 43 System.out.println("B from" + Thread.currentThread().getName() + " get put data :" + data); 44 } 45 }
时间: 2024-10-11 07:35:33