首页 > 编程语言 > 详细

Java多线程并发库API使用

时间:2016-04-18 02:02:16      阅读:223      评论:0      收藏:0      [点我收藏+]

1.??????? 传统线程技术回顾

继承线程与实现Runnable的差异?为什么那么多人都采取第二种方式?

因为第二种方式更符合面向对象的思维方式。创建一个线程,线程要运行代码,而运行的代码都封装到一个独立的对象中去。一个叫线程,一个叫线程运行的代码,这是两个东西。两个东西一组合,就表现出了面向对象的思维。如果两个线程实现数据共享,必须用Runnable的方式。

查看Thread类的run()方法的源代码,可以看到其实这两种方式都是在调用Thread对象的run方法,如果Thread类的run方法没有被覆盖,并且为该Thread对象设置了一个Runnable对象,该run方法会调用Runnable对象的run方法。

问题如果在Thread子类覆盖的run方法中编写了运行代码,也为Thread子类对象传递了一个Runnable对象,那么,线程运行时的执行代码是子类的run方法的代码?还是Runnable对象的run方法的代码?子类的run方法。

示例代码

?

?
 1     new Thread(new Runnable() {
 2         public void run() {
 3             while (true) {
 4                 System.out.println("run:runnable");
 5             }
 6         }
 7     }) {
 8         public void run() {
 9             while (true) {
10                 try {
11                     Thread.sleep(1000);
12                 } catch (Exception e) {
13                 }
14                 System.out.println("run:thread");
15             }
16         }
17     }.start();
?

?

该线程会运行重写的Thread中的run方法,而不是Runnable中的run方法,因为在传统的Thread的run方法是:

1     public void run() {
2         if (target != null) {
3             target.run();
4         }   
5     }

?

如果想要运行Runnable中的run方法,必须在Thread中调用,但是此时我重写了Thread中的run方法,导致if (target != null) {? target.run();???? }不存在,所以调用不了Runnable中的run方法。

注意:多线程的执行,会提高程序的运行效率吗?为什么会有多线程下载?

不会,有时候还会降低程序的运行效率。因为CPU只有一个,在CPU上下文切换的时候,可能还会耽误时间。

多线程下载:其实你的机器没有变快,而是你抢了服务器的带宽。如果你一个人下载,服务器给你提供的是20K的话,那么10个人的话,服务器提供的就是200K。这个时候你抢走200k,所以感觉变快了。

2.??????? 传统定时器技术回顾(jdk1.5以前)Timer、TimerTask

Timer:一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。

scheduleAtFixedRate(TimerTask?task,?Date?firstTime, long?period):

安排指定的任务在指定的时间开始进行重复的固定速率执行。

schedule(TimerTask?task, long?delay, long?period):?安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。

作业调度框架 Quartz(专门用来处理时间时间的工具)。你能够用它来为执行一个作业而创建简单的或复杂的调度。{ http://www.oschina.net/p/quartz}

问题:每天早晨3点来送报纸。

问题:每个星期周一到周五上班,周六道周日不上班。

示例代码:(间隔不同时间,执行不同事件)

?
 1 package com.chunjiangchao.thread;
 2 
 3 import java.util.Timer;
 4 import java.util.TimerTask;
 5 /**
 6  * 重复执行某项任务,但是时间间隔性不同是2,4这种状态
 7  * @author chunjiangchao
 8  *
 9  */
10 public class TimerDemo02 {
11     
12     private static long count = 1;
13     public static void main(String[] args) {
14         Timer timer =  new Timer();
15         timer.schedule(new Task(), 1000);
16         /*
17              测试打印结果如下:
18              执行任务,当前时间为:1460613231
19             执行任务,当前时间为:1460613235
20             执行任务,当前时间为:1460613237
21             执行任务,当前时间为:1460613241
22          */
23         
24     new Thread(new Runnable() {
25         public void run() {
26             while (true) {
27                 System.out.println("run:runnable");
28             }
29         }
30     }) {
31         public void run() {
32             while (true) {
33                 try {
34                     Thread.sleep(1000);
35                 } catch (Exception e) {
36                 }
37                 System.out.println("run:thread");
38             }
39         }
40     }.start();
41 
42         
43     }
44     
45     static class Task extends TimerTask{
46 
47         @Override
48         public void run() {
49             System.out.println("执行任务,当前时间为:"+System.currentTimeMillis()/1000);
50             new Timer().schedule(new Task(), 2000*(1+count%2));
51             count++;
52         }
53         
54     }
55 
56 }
?

?

3.??????? 传统线程互斥技术

本道例题:关键在于说明:要想实现线程间的互斥,线程数量必须达到两个或者两个以上,同时,访问资源的时候要用同一把锁(这个是必须的)。如果两个线程都访问不同的同步代码块,而且它们的锁对象都不相同,那么这些线程就没有达到同步的目的。

示例代码:(访问同一个资源对象,但是锁对象不同,同样没有达到同步的目的)

?View Code

?

4.??????? 传统线程同步通信技术

在设计的时候,最好将相关的代码封装到一个类中,不仅可以方便处理,还可以实现内部的高耦合。

问题示例图

bubuko.com,布布扣

?

经验总结:要用到共同数据(包括同步锁)或共同算法的若干个方法应该归在同一个类身上,这种设计正好体现了高类聚和程序的健壮性。

同步通信,互斥的问题不是写在线程上面的,而是直接写在资源里面的,线程是直接拿过来使用就可以了。好处就是,以后我的类,交给任何一个线程去访问,它天然就同步了,不需要考虑线程同步的问题。如果是在线程上面写,明天又有第三个线程来调用我,还得在第三个线程上面写互斥写同步。(全部在资源类的内部写,而不是在线程的代码上面去写)

示例代码:(子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100, 如此循环50次,请写出程序。)

?
 1 package com.chunjiangchao.thread;
 2 
 3 public class TraditionalThreadCommunication {
 4     /**
 5      * 经验:涉及到线程互斥共享,应该想到将同步方法写在资源里面,而不是写在线程代码块中 在资源中判断标记的时候,最好用while语句
 6      */
 7     public static void main(String[] args) {
 8         final Output output = new Output();
 9         new Thread(new Runnable() {
10             public void run() {
11                 for (int i = 0; i < 50; i++) {
12                     output.sub(10);
13                 }
14             }
15         }).start();
16         for (int i = 0; i < 50; i++) {
17             output.main(i);
18         }
19     }
20 }
21 
22 class Output {
23     private boolean flag = true;
24 
25     public synchronized void sub(int i) {
26         while (!flag) {// 用while比用if更加健壮,原因是即使线程被唤醒了,也判断一下是不是真的该它执行了
27                         // 防止伪唤醒的事件发生。
28             try {
29                 this.wait();
30             } catch (InterruptedException e) {
31             }
32         }
33         for (int j = 0; j < 10; j++) {
34             System.out.println(i + "子线程运行" + j);
35         }
36         flag = false;// 记得要改变一下标记的状态
37         this.notify();// 最后要唤醒其他要使用该锁的线程
38     }
39 
40     public synchronized void main(int i) {
41         while (flag) {
42             try {
43                 this.wait();
44             } catch (InterruptedException e) {
45             }
46         }
47         for (int j = 0; j < 100; j++) {
48             System.out.println(i + "主线程运行" + j);
49         }
50         flag = true;
51         this.notify();
52     }
53 }
?

?

5.??????? 线程范围内共享变量的概念与作用

线程范围内的数据共享:不管是A模块,还B模块,如果他们在同一个线程上运行,那么他们操作的数据应该是相同。而不应该是不管A模块和B模块在哪个线程上面运行他们的数据在每个线程中的数据是一样的。(应该是各自线程上的数据是独立的)

线程间的事务处理:

如图:

bubuko.com,布布扣

不能出现这样的情况:thread1转入的data,还没有来得及操作。CPU时间片转入到thread2,该thread2来执行,转入、转出,最后直接提交事务。导致thread1的数据出现错误。

线程范围内的变量有什么用?

我这件事务在线程范围内搞定,不要去影响别的线程的事务。但是我这个线程内,几个模块之间是独立的,这几个模块又要共享同一个对象。它们既要共享又要独立,在线程内共享,在线程外独立。【对于相同的程序代码,多个模块在同一个线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据。】

示例代码(不同线程之间共享同一个Map对象,但是Map中的每个元素表示的是不同线程的数据)

?
 1 package com.chunjiangchao.thread;
 2 
 3 import java.util.HashMap;
 4 import java.util.Map;
 5 import java.util.Random;
 6 
 7 /**
 8  * 线程范围内共享数据
 9  * @author chunjiangchao
10  *
11  */
12 public class ThreadScopeShareDataDemo {
13     //所有线程共享的数据是datas,但是datas中的每个元素key是Thread,每个元素针对每个线程来说是独立的,value代表不同线程处理的数据
14     private static Map<Thread,Integer> datas = new HashMap<Thread,Integer>();
15     public static void main(String[] args) {
16         for(int i=0;i<2;i++){
17             new Thread(new Runnable() {
18                 
19                 @Override
20                 public void run() {
21                     int nextInt = new Random().nextInt();
22                     datas.put(Thread.currentThread(), nextInt);
23                     ///A模块与B模块是独立的,但是A与B共享当前当前线程中的数据
24                     new ModuleA().getThreadData();
25                     new ModuleB().getThreadData();
26                 }
27             }).start();
28         }
29         /*
30              打印的结果为
31              Thread-1的ModuleA获取的变量为:-918049793
32             Thread-0的ModuleA获取的变量为:-1424853148
33             Thread-0的ModuleB获取的变量为:-1424853148
34             Thread-1的ModuleB获取的变量为:-918049793
35  
36          */
37     }
38     static class ModuleA{
39         public void getThreadData(){
40             System.out.println(Thread.currentThread().getName()+"的ModuleA获取的变量为:"+datas.get(Thread.currentThread()));
41         }
42     }
43     static class ModuleB{
44         public void getThreadData(){
45             System.out.println(Thread.currentThread().getName()+"的ModuleB获取的变量为:"+datas.get(Thread.currentThread()));
46         }
47     }
48 
49 }
?

6.??????? ThreadLocal类及应用技巧

ThreadLocal就相当于一个Map。

一个ThreadLocal代表一个变量,故其中只能放一个数据,你有两个变量都要线程范围内共享,则要定义两个ThreadLocal对象,如果有一个一百个变量要线程共享?那么就应该定义一个对象来装着一百个变量,然后在ThreadLocal中存储这一个对象。

问题:怎么在线程结束的时候得到通知?提示:监听虚拟机结束。

最重要的一点,就是里面涉及到的设计方法。

bubuko.com,布布扣
获取【下载地址】? ?QQ: 313596790? ?【免费支持更新】
三大数据库 mysql??oracle??sqlsever? ?更专业、更强悍、适合不同用户群体
新录针对本系统的视频教程,手把手教开发一个模块,快速掌握本系统

A 集成代码生成器(开发利器)+快速构建表单;? ?? ?? ?? ?QQ:313596790
freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面、建表sql脚本,处理类,service等完整模块
B 集成阿里巴巴数据库连接池druid;
??数据库连接池??阿里巴巴的 druid。Druid在监控、可扩展性、稳定性和性能方面都有明显的优势
C 集成安全权限框架shiro ;
??Shiro 是一个用 Java 语言实现的框架,通过一个简单易用的 API 提供身份验证和授权,更安全,更可靠
D 集成ehcache 分布式缓存 ;
??是一个纯Java的进程内缓存框架,具有快速、精干等特点,广泛使用的开源Java分布式缓存。
E 集成微信接口开发;? ? F 图片爬虫技术;? ?G??SQL 编辑器, 支持复杂sql语句,生成报表,可以导出excel
H websocket及时通讯技术(即时聊天、及时站内信并声音提醒、实时在线管理、websocket及时刷新页面);
-------------------------------------------------------------------------------------------------------------------------

Java多线程并发库API使用

原文:http://dufh475ia.iteye.com/blog/2291379

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!