Java5 多线程(一)--入门篇
首先回顾一下JDK1.5之前的线程相关的知识:1 线程的入门.
什么是线程,线程就是程序执行的线索,Java是面向对象的语言什么类来表示这样一个东西呢?Thread.
通过start()方法启动它,线程所要执行的任务放在run()方法里面,下面可以看一下run()方法里面的源码
创建线程的两种传统方式(注: Runnable类并不是一个线程,它只是线程一个执行单元):
打开Thread的构造方法,
然后可以跟进看到init()方法具体的实现.其中有一行代码就是对target(Runnable类型)的赋值,因为线程所执行的任务都在run()方法里面,那么在run()方法里面,target就不为null,然后就调用了Runnale的run()方法.因为我们重写了Runnable的run()方法,那么最终执行的就是我们所覆写的run()方法.具体代码如下:
如果我们同时实现了Thread的run()方法又同时覆盖了Runnable的run()方法.那么到底会执行哪个的run()方法呢?
根据Java的多态,肯定执行的是Thread的run()方法.因为我们覆写了Thread的run()方法,那么所执行的就是我们run()方法,而不是
2 传统的定时器:
定时器通过Timer这个类来描述,通过schedule()方法来调度,定时执行的任务通过TimerTask来定义.
下面来实现一个简单的定时器,功能如下,每隔2秒执行一次,之后隔4秒执行一次,然后又隔2秒,就这样轮循下去.具体用法可以查看API里面有详细介绍.
[java]
public static void main(String[] args) { new Timer().schedule(new MyTimerTask(), 2000); try { while (true) { System.out.println(new Date().getSeconds()); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } } class MyTimerTask extends TimerTask { static int count = 0; @Override public void run() { count = (count + 1) % 2;//count=0或1 System.out.println("boming"); Timer timer = new Timer(); timer.schedule(new MyTimerTask(), 2000 + (2000) * count); }
3 线程之间的互斥和同步通信
当两个线程去同时操作一个字符串,那么可能会出现线程安全问题.这样的情况可以用银行转帐来解释.
下面的代码就会出现问题,
[java]
public static void main(String[] args) { final Outputer outputer = new Outputer(); new Thread() { @Override public void run() { while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } outputer.print("zhangsan"); } } }.start(); new Thread() { @Override public void run() { while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } outputer.print("zhangxiaoxiang"); } } }.start(); } } class Outputer { public void print(String name) { for (int i = 0; i < name.length(); i++) { System.out.print(name.charAt(i)); } System.out.println();// 打印完字符串换行 } }
我们使用两个线程去调用print(String name)方法,当第一个方法还没有执行完毕,第二个方法来执行,那么打印出来的name就会出现为问题.如下图所示,
现在我们要实现的是,只有当第一个线程执行完毕后,第二个线程才能执行print(String name)方法,这就必须互斥或者说同步.
我们知道实现同步可以使用同步代码块或者同步方法,想到同步(Synchronized)那么自然而然就想到同步监视器.
这是两个很重要的概念.
现在我们来改造上面Outputer的print(String name)方法.
[java]
public void print(String name) {
//synchronized()里面的参数就是同步监视器
//然而这里使用name作为同步监视器是不行的,
//因为要实现原子性(互斥)必须要使用同一个监视器对象
//当第一个线程来执行该代码块,name对象是一个String对象
//当第二个线程来执行,name对象又是另一个String对象,
//这样就不能实现同步
synchronized (name) {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();// 打印完字符串换行
}
}
执行结果如下所示:
我们可以通过this关键字作为同步监视器,因为从上面定义两个线程的代码来看,我们只new了一次Outputer对象,所以this代表同一个对象.
现在来通过同步方法来实现同步,
[java]
//同步方法也同样也有同步监视器,它是this
public synchronized void print2(String name) {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();// 打印完字符串换行
}
把第二个线程改成使用print2(String name)方法.这样的话就需要print2和print这两个方法互斥.这个怎么理解呢?
上面我们是对print()这个一个方法进行互斥,现在呢?需要对两个方法进行互斥.
我们可以这样比喻(对一个方法进行互斥):假设一个茅坑(print(String name)),上面有一把锁(this对象),现在一个人(Thread)来上厕所,它把钥匙放进了口袋,第二个人(Thread2)来上厕所,因为没有钥匙,必须要等第一个人出来,把钥匙放上去,第二个人才能拿着钥匙进去.这是对一个方法进行同步,
(对两个方法或者更多进行同步)),现在有多个茅坑(print(String name),print2(String name)),只有一个钥匙(同步监视器),那么当一个人(Thread)进去后,拿了那仅有的一个钥匙,就算其他人(Thread)想进入的没有人占的茅坑也不行,因为没有钥匙.
这样的话,打印name的时候就不会出现问题.
现在还有一种情况:
[java]
//静态的同步方法同样也有同步监视器,它是class
public static synchronized void print3(String name) {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();// 打印完字符串换行
}
这样的话要想互斥就必须把同步监视器改成Outputer.class了,在内存中只有一份.
线程之间的同步通信
通过一道面试提来解释.
子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序。
[java]
//静态的同步方法同样也有同步监视器,它是class
public static synchronized void print3(String name) {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i));
}
System.out.println();// 打印完字符串换行
}
这样的话要想互斥就必须把同步监视器改成Outputer.class了,在内存中只有一份.
线程之间的同步通信
通过一道面试提来解释.
子线程循环10次,接着主线程循环100,接着又回到子线程循环10次,接着再回到主线程又循环100,如此循环50次,请写出程序。
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for (int k = 1; k <= 50; k++) {
for (int i = 1; i <= 10; i++) {
System.out.println("sub thread sequence " + i
+ " loop of " + k);
}
}
}
}).start();
for (int k = 1; k <= 50; k++) {
for (int i = 1; i <= 100; i++) {
System.out
.println("main thread sequen补充:软件开发 , Java ,
- 更多JAVA疑问解答:
- java怎么在线读取ftp服务器上的文件内容
- 关于程序员的职业规划
- HTML和JSP矛盾吗?
- java小程序如何打包?
- java怎么split路径文件名?
- 关于Hibernate实体自身多对一的抓取问题
- 关于apache2+tomcat群集出现的问题
- SSH 导入导出excel 谁有这块的资料吗?
- springmvc 加载一个jsp页面执行多个方法 报404
- 关于用jquery 导入 excel
- java对时间进行循环放到List中
- 一个图片的输入输出程序,第一次调用某方法会中断,第二次调用则正常
- 请上过传智播客的人说一下传智播客怎么样呀!是不是像它说的那样好呀!
- spring的schema怎么配置
- 【菜鸟求助】SSH中怎么从JSP页面往后台传值呢