- 浏览: 115450 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
天助者自助:
我想问一下 我获取的时候 我获取的时候 这样 requ ...
struts2的@Result annotation 如何添加params -
aslijiasheng:
不错,学习了
java中queue的使用 -
JavaFinger:
这篇文章写的非常好,博主厉害,但是例子不太好,博主能不能把例子 ...
java中queue的使用
在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口。
对于直接继承Thread的类来说,代码大致框架是:
先看一个简单的例子:
【运行结果】:
A运行 0
A运行 1
A运行 2
A运行 3
A运行 4
B运行 0
B运行 1
B运行 2
B运行 3
B运行 4
我们会发现这些都是顺序执行的,说明我们的调用方法不对,应该调用的是start()方法。
当我们把上面的主函数修改为如下所示的时候:
然后运行程序,输出的可能的结果如下:
A运行 0
B运行 0
B运行 1
B运行 2
B运行 3
B运行 4
A运行 1
A运行 2
A运行 3
A运行 4
因为需要用到CPU的资源,所以每次的运行结果基本是都不一样的,呵呵。
注意:虽然我们在这里调用的是start()方法,但是实际上调用的还是run()方法的主体。
那么:为什么我们不能直接调用run()方法呢?
我的理解是:线程的运行需要本地操作系统的支持。
如果你查看start的源代码的时候,会发现:
注意我用红色加粗的那一条语句,说明此处调用的是start0()。并且这个这个方法用了native关键字,次关键字表示调用本地操作系统的函数。因为多线程的实现需要本地操作系统的支持。
但是start方法重复调用的话,会出现java.lang.IllegalThreadStateException异常。
通过实现Runnable接口:
大致框架是:
来先看一个小例子吧:
【可能的运行结果】:
线程A运行 0
线程B运行 0
线程B运行 1
线程B运行 2
线程B运行 3
线程B运行 4
线程A运行 1
线程A运行 2
线程A运行 3
线程A运行 4
关于选择继承Thread还是实现Runnable接口?
其实Thread也是实现Runnable接口的:
其实Thread中的run方法调用的是Runnable接口的run方法。不知道大家发现没有,Thread和Runnable都实现了run方法,这种操作模式其实就是代理模式。关于代理模式,我曾经写过一个小例子呵呵,大家有兴趣的话可以看一下:http://www.cnblogs.com/rollenholt/archive/2011/08/18/2144847.html
Thread和Runnable的区别:
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
【运行结果】:
count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1
大家可以想象,如果这个是一个买票系统的话,如果count表示的是车票的数量的话,说明并没有实现资源的共享。
我们换为Runnable接口:
【运行结果】:
count= 5
count= 4
count= 3
count= 2
count= 1
总结一下吧:
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
所以,本人建议大家劲量实现接口。
【运行结果】:
A
A
A
B
B
B
Thread-0
Thread-0
Thread-0
说明如果我们没有指定名字的话,系统自动提供名字。
提醒一下大家:main方法其实也是一个线程。在java中所以的线程都是同时启动的,至于什么时候,哪个先执行,完全看谁先得到CPU的资源。
在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个jVM实习在就是在操作系统中启动了一个进程。
判断线程是否启动
【运行结果】
线程启动之前---》false
线程启动之后---》true
Thread-0
Thread-0
Thread-0
主线程也有可能在子线程结束之前结束。并且子线程不受影响,不会因为主线程的结束而结束。
线程的强制执行:
【运行的结果】:
main 线程执行-->0
main 线程执行-->1
main 线程执行-->2
main 线程执行-->3
main 线程执行-->4
main 线程执行-->5
main 线程执行-->6
main 线程执行-->7
main 线程执行-->8
main 线程执行-->9
main 线程执行-->10
线程
线程
线程
main 线程执行-->11
main 线程执行-->12
main 线程执行-->13
...
线程的休眠:
【运行结果】:(结果每隔2s输出一个)
线程0
线程1
线程2
线程的中断:
【运行结果】:
执行run方法
休眠被打断
在java程序中,只要前台有一个线程在运行,整个java程序进程不会消失,所以此时可以设置一个后台线程,这样即使java进程消失了,此后台线程依然能够继续运行
虽然有一个死循环,但是程序还是可以执行完的。因为在死循环中的线程操作已经设置为后台运行了。
线程的优先级:
虽然有一个死循环,但是程序还是可以执行完的。因为在死循环中的线程操作已经设置为后台运行了。
线程的优先级:
【运行结果】:
A运行0
A运行1
A运行2
A运行3
A运行4
B运行0
C运行0
C运行1
C运行2
C运行3
C运行4
B运行1
B运行2
B运行3
B运行4
。但是请读者不要误以为优先级越高就先执行。谁先执行还是取决于谁先去的CPU的资源、
另外,主线程的优先级是5.
线程的礼让。
在线程操作中,也可以使用yield()方法,将一个线程的操作暂时交给其他线程执行。
A运行0
A运行1
A运行2
A运行3
线程的礼让
A运行4
B运行0
B运行1
B运行2
B运行3
线程的礼让
B运行4
同步和死锁:
【问题引出】:比如说对于买票系统,有下面的代码:
【运行结果】:
5
4
3
2
1
0
-1
这里出现了-1,显然这个是错的。,应该票数不能为负值。
如果想解决这种问题,就需要使用同步。所谓同步就是在统一时间段中只有有一个线程运行,
其他的线程必须等到这个线程结束之后才能继续执行。
【使用线程同步解决问题】
采用同步的话,可以使用同步代码块和同步方法两种来完成。
【同步代码块】:
语法格式:
synchronized(同步对象){
//需要同步的代码
}
但是一般都把当前对象this作为同步对象。
比如对于上面的买票的问题,如下:
【运行结果】:(每一秒输出一个结果)
5
4
3
2
1
【同步方法】
也可以采用同步方法。
语法格式为
现在,我们采用同步方法解决上面的问题。
【运行结果】(每秒输出一个)
5
4
3
2
1
提醒一下,当多个线程共享一个资源的时候需要进行同步,但是过多的同步可能导致死锁。
此处列举经典的生产者和消费者问题。
【生产者和消费者问题】
先看一段有问题的代码。
【运行结果】:
Rollen<---->100
chunGe<---->20
chunGe<---->100
Rollen<---->100
chunGe<---->20
Rollen<---->100
Rollen<---->100
Rollen<---->100
chunGe<---->20
chunGe<---->20
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
大家可以从结果中看到,名字和年龄并没有对上。
那么如何解决呢?
加入同步
加入等待和唤醒
先来看看加入同步会是如何。
【运行结果】:
Rollen<===>20
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
从运行结果来看,错乱的问题解决了,现在是Rollen 对应20,ChunGe对于100
,但是还是出现了重复读取的问题,也肯定有重复覆盖的问题。如果想解决这个问题,就需要使用Object类帮忙了、
,我们可以使用其中的等待和唤醒操作。
要完成上面的功能,我们只需要修改Info类饥渴,在其中加上标志位,并且通过判断标志位完成等待和唤醒的操作,代码如下:
《完》
对于直接继承Thread的类来说,代码大致框架是:
class 类名 extends Thread{ 方法1; 方法2; … public void run(){ // other code… } 属性1; 属性2; … }
先看一个简单的例子:
/** * @author Rollen-Holt 继承Thread类,直接调用run方法 * */ class hello extends Thread { public hello() { } public hello(String name) { this.name = name; } public void run() { for (int i = 0; i < 5; i++) { System.out.println(name + "运行 " + i); } } public static void main(String[] args) { hello h1=new hello("A"); hello h2=new hello("B"); h1.run(); h2.run(); } private String name; }
【运行结果】:
A运行 0
A运行 1
A运行 2
A运行 3
A运行 4
B运行 0
B运行 1
B运行 2
B运行 3
B运行 4
我们会发现这些都是顺序执行的,说明我们的调用方法不对,应该调用的是start()方法。
当我们把上面的主函数修改为如下所示的时候:
public static void main(String[] args) { hello h1=new hello("A"); hello h2=new hello("B"); h1.start(); h2.start(); }
然后运行程序,输出的可能的结果如下:
A运行 0
B运行 0
B运行 1
B运行 2
B运行 3
B运行 4
A运行 1
A运行 2
A运行 3
A运行 4
因为需要用到CPU的资源,所以每次的运行结果基本是都不一样的,呵呵。
注意:虽然我们在这里调用的是start()方法,但是实际上调用的还是run()方法的主体。
那么:为什么我们不能直接调用run()方法呢?
我的理解是:线程的运行需要本地操作系统的支持。
如果你查看start的源代码的时候,会发现:
public synchronized void start() { /** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state "NEW". */ if (threadStatus != 0 || this != me) throw new IllegalThreadStateException(); group.add(this); start0(); if (stopBeforeStart) { stop0(throwableFromStop); } } private native void start0();
注意我用红色加粗的那一条语句,说明此处调用的是start0()。并且这个这个方法用了native关键字,次关键字表示调用本地操作系统的函数。因为多线程的实现需要本地操作系统的支持。
但是start方法重复调用的话,会出现java.lang.IllegalThreadStateException异常。
通过实现Runnable接口:
大致框架是:
class 类名 implements Runnable{ 方法1; 方法2; … public void run(){ // other code… } 属性1; 属性2; … }
来先看一个小例子吧:
/** * @author Rollen-Holt 实现Runnable接口 * */ class hello implements Runnable { public hello() { } public hello(String name) { this.name = name; } public void run() { for (int i = 0; i < 5; i++) { System.out.println(name + "运行 " + i); } } public static void main(String[] args) { hello h1=new hello("线程A"); Thread demo= new Thread(h1); hello h2=new hello("线程B"); Thread demo1=new Thread(h2); demo.start(); demo1.start(); } private String name; }
【可能的运行结果】:
线程A运行 0
线程B运行 0
线程B运行 1
线程B运行 2
线程B运行 3
线程B运行 4
线程A运行 1
线程A运行 2
线程A运行 3
线程A运行 4
关于选择继承Thread还是实现Runnable接口?
其实Thread也是实现Runnable接口的:
class Thread implements Runnable { //… public void run() { if (target != null) { target.run(); } } }
其实Thread中的run方法调用的是Runnable接口的run方法。不知道大家发现没有,Thread和Runnable都实现了run方法,这种操作模式其实就是代理模式。关于代理模式,我曾经写过一个小例子呵呵,大家有兴趣的话可以看一下:http://www.cnblogs.com/rollenholt/archive/2011/08/18/2144847.html
Thread和Runnable的区别:
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
/** * @author Rollen-Holt 继承Thread类,不能资源共享 * */ class hello extends Thread { public void run() { for (int i = 0; i < 7; i++) { if (count > 0) { System.out.println("count= " + count--); } } } public static void main(String[] args) { hello h1 = new hello(); hello h2 = new hello(); hello h3 = new hello(); h1.start(); h2.start(); h3.start(); } private int count = 5; }
【运行结果】:
count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1
count= 5
count= 4
count= 3
count= 2
count= 1
大家可以想象,如果这个是一个买票系统的话,如果count表示的是车票的数量的话,说明并没有实现资源的共享。
我们换为Runnable接口:
/** * @author Rollen-Holt 继承Thread类,不能资源共享 * */ class hello implements Runnable { public void run() { for (int i = 0; i < 7; i++) { if (count > 0) { System.out.println("count= " + count--); } } } public static void main(String[] args) { hello he=new hello(); new Thread(he).start(); } private int count = 5; }
【运行结果】:
count= 5
count= 4
count= 3
count= 2
count= 1
总结一下吧:
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
所以,本人建议大家劲量实现接口。
/** * @author Rollen-Holt * 取得线程的名称 * */ class hello implements Runnable { public void run() { for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName()); } } public static void main(String[] args) { hello he = new hello(); new Thread(he,"A").start(); new Thread(he,"B").start(); new Thread(he).start(); } }
【运行结果】:
A
A
A
B
B
B
Thread-0
Thread-0
Thread-0
说明如果我们没有指定名字的话,系统自动提供名字。
提醒一下大家:main方法其实也是一个线程。在java中所以的线程都是同时启动的,至于什么时候,哪个先执行,完全看谁先得到CPU的资源。
在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个jVM实习在就是在操作系统中启动了一个进程。
判断线程是否启动
/** * @author Rollen-Holt 判断线程是否启动 * */ class hello implements Runnable { public void run() { for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName()); } } public static void main(String[] args) { hello he = new hello(); Thread demo = new Thread(he); System.out.println("线程启动之前---》" + demo.isAlive()); demo.start(); System.out.println("线程启动之后---》" + demo.isAlive()); } }
【运行结果】
线程启动之前---》false
线程启动之后---》true
Thread-0
Thread-0
Thread-0
主线程也有可能在子线程结束之前结束。并且子线程不受影响,不会因为主线程的结束而结束。
线程的强制执行:
/** * @author Rollen-Holt 线程的强制执行 * */ class hello implements Runnable { public void run() { for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName()); } } public static void main(String[] args) { hello he = new hello(); Thread demo = new Thread(he,"线程"); demo.start(); for(int i=0;i<50;++i){ if(i>10){ try{ demo.join(); //强制执行demo }catch (Exception e) { e.printStackTrace(); } } System.out.println("main 线程执行-->"+i); } } }
【运行的结果】:
main 线程执行-->0
main 线程执行-->1
main 线程执行-->2
main 线程执行-->3
main 线程执行-->4
main 线程执行-->5
main 线程执行-->6
main 线程执行-->7
main 线程执行-->8
main 线程执行-->9
main 线程执行-->10
线程
线程
线程
main 线程执行-->11
main 线程执行-->12
main 线程执行-->13
...
线程的休眠:
/** * @author Rollen-Holt 线程的休眠 * */ class hello implements Runnable { public void run() { for (int i = 0; i < 3; i++) { try { Thread.sleep(2000); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + i); } } public static void main(String[] args) { hello he = new hello(); Thread demo = new Thread(he, "线程"); demo.start(); } }
【运行结果】:(结果每隔2s输出一个)
线程0
线程1
线程2
线程的中断:
/** * @author Rollen-Holt 线程的中断 * */ class hello implements Runnable { public void run() { System.out.println("执行run方法"); try { Thread.sleep(10000); System.out.println("线程完成休眠"); } catch (Exception e) { System.out.println("休眠被打断"); return; //返回到程序的调用处 } System.out.println("线程正常终止"); } public static void main(String[] args) { hello he = new hello(); Thread demo = new Thread(he, "线程"); demo.start(); try{ Thread.sleep(2000); }catch (Exception e) { e.printStackTrace(); } demo.interrupt(); //2s后中断线程 } }
【运行结果】:
执行run方法
休眠被打断
在java程序中,只要前台有一个线程在运行,整个java程序进程不会消失,所以此时可以设置一个后台线程,这样即使java进程消失了,此后台线程依然能够继续运行
/** * @author Rollen-Holt 后台线程 * */ class hello implements Runnable { public void run() { while (true) { System.out.println(Thread.currentThread().getName() + "在运行"); } } public static void main(String[] args) { hello he = new hello(); Thread demo = new Thread(he, "线程"); demo.setDaemon(true); demo.start(); } }
虽然有一个死循环,但是程序还是可以执行完的。因为在死循环中的线程操作已经设置为后台运行了。
线程的优先级:
/** * @author Rollen-Holt 后台线程 * */ class hello implements Runnable { public void run() { while (true) { System.out.println(Thread.currentThread().getName() + "在运行"); } } public static void main(String[] args) { hello he = new hello(); Thread demo = new Thread(he, "线程"); demo.setDaemon(true); demo.start(); } }
虽然有一个死循环,但是程序还是可以执行完的。因为在死循环中的线程操作已经设置为后台运行了。
线程的优先级:
/** * @author Rollen-Holt 线程的优先级 * */ class hello implements Runnable { public void run() { for(int i=0;i<5;++i){ System.out.println(Thread.currentThread().getName()+"运行"+i); } } public static void main(String[] args) { Thread h1=new Thread(new hello(),"A"); Thread h2=new Thread(new hello(),"B"); Thread h3=new Thread(new hello(),"C"); h1.setPriority(8); h2.setPriority(2); h3.setPriority(6); h1.start(); h2.start(); h3.start(); } }
【运行结果】:
A运行0
A运行1
A运行2
A运行3
A运行4
B运行0
C运行0
C运行1
C运行2
C运行3
C运行4
B运行1
B运行2
B运行3
B运行4
。但是请读者不要误以为优先级越高就先执行。谁先执行还是取决于谁先去的CPU的资源、
另外,主线程的优先级是5.
线程的礼让。
在线程操作中,也可以使用yield()方法,将一个线程的操作暂时交给其他线程执行。
/** * @author Rollen-Holt 线程的优先级 * */ class hello implements Runnable { public void run() { for(int i=0;i<5;++i){ System.out.println(Thread.currentThread().getName()+"运行"+i); if(i==3){ System.out.println("线程的礼让"); Thread.currentThread().yield(); } } } public static void main(String[] args) { Thread h1=new Thread(new hello(),"A"); Thread h2=new Thread(new hello(),"B"); h1.start(); h2.start(); } }
A运行0
A运行1
A运行2
A运行3
线程的礼让
A运行4
B运行0
B运行1
B运行2
B运行3
线程的礼让
B运行4
同步和死锁:
【问题引出】:比如说对于买票系统,有下面的代码:
/** * @author Rollen-Holt * */ class hello implements Runnable { public void run() { for(int i=0;i<10;++i){ if(count>0){ try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(count--); } } } public static void main(String[] args) { hello he=new hello(); Thread h1=new Thread(he); Thread h2=new Thread(he); Thread h3=new Thread(he); h1.start(); h2.start(); h3.start(); } private int count=5; }
【运行结果】:
5
4
3
2
1
0
-1
这里出现了-1,显然这个是错的。,应该票数不能为负值。
如果想解决这种问题,就需要使用同步。所谓同步就是在统一时间段中只有有一个线程运行,
其他的线程必须等到这个线程结束之后才能继续执行。
【使用线程同步解决问题】
采用同步的话,可以使用同步代码块和同步方法两种来完成。
【同步代码块】:
语法格式:
synchronized(同步对象){
//需要同步的代码
}
但是一般都把当前对象this作为同步对象。
比如对于上面的买票的问题,如下:
/** * @author Rollen-Holt * */ class hello implements Runnable { public void run() { for(int i=0;i<10;++i){ synchronized (this) { if(count>0){ try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(count--); } } } } public static void main(String[] args) { hello he=new hello(); Thread h1=new Thread(he); Thread h2=new Thread(he); Thread h3=new Thread(he); h1.start(); h2.start(); h3.start(); } private int count=5; }
【运行结果】:(每一秒输出一个结果)
5
4
3
2
1
【同步方法】
也可以采用同步方法。
语法格式为
synchronized 方法返回类型 方法名(参数列表){ // 其他代码 }
现在,我们采用同步方法解决上面的问题。
/** * @author Rollen-Holt * */ class hello implements Runnable { public void run() { for (int i = 0; i < 10; ++i) { sale(); } } public synchronized void sale() { if (count > 0) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(count--); } } public static void main(String[] args) { hello he = new hello(); Thread h1 = new Thread(he); Thread h2 = new Thread(he); Thread h3 = new Thread(he); h1.start(); h2.start(); h3.start(); } private int count = 5; }
【运行结果】(每秒输出一个)
5
4
3
2
1
提醒一下,当多个线程共享一个资源的时候需要进行同步,但是过多的同步可能导致死锁。
此处列举经典的生产者和消费者问题。
【生产者和消费者问题】
先看一段有问题的代码。
class Info { public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } private String name = "Rollen"; private int age = 20; } /** * 生产者 * */ class Producer implements Runnable{ private Info info=null; Producer(Info info){ this.info=info; } public void run(){ boolean flag=false; for(int i=0;i<25;++i){ if(flag){ this.info.setName("Rollen"); try{ Thread.sleep(100); }catch (Exception e) { e.printStackTrace(); } this.info.setAge(20); flag=false; }else{ this.info.setName("chunGe"); try{ Thread.sleep(100); }catch (Exception e) { e.printStackTrace(); } this.info.setAge(100); flag=true; } } } } /** * 消费者类 * */ class Consumer implements Runnable{ private Info info=null; public Consumer(Info info){ this.info=info; } public void run(){ for(int i=0;i<25;++i){ try{ Thread.sleep(100); }catch (Exception e) { e.printStackTrace(); } System.out.println(this.info.getName()+"<---->"+this.info.getAge()); } } } /** * 测试类 * */ class hello{ public static void main(String[] args) { Info info=new Info(); Producer pro=new Producer(info); Consumer con=new Consumer(info); new Thread(pro).start(); new Thread(con).start(); } }
【运行结果】:
Rollen<---->100
chunGe<---->20
chunGe<---->100
Rollen<---->100
chunGe<---->20
Rollen<---->100
Rollen<---->100
Rollen<---->100
chunGe<---->20
chunGe<---->20
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
Rollen<---->100
chunGe<---->20
大家可以从结果中看到,名字和年龄并没有对上。
那么如何解决呢?
加入同步
加入等待和唤醒
先来看看加入同步会是如何。
class Info { public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public synchronized void set(String name, int age){ this.name=name; try{ Thread.sleep(100); }catch (Exception e) { e.printStackTrace(); } this.age=age; } public synchronized void get(){ try{ Thread.sleep(100); }catch (Exception e) { e.printStackTrace(); } System.out.println(this.getName()+"<===>"+this.getAge()); } private String name = "Rollen"; private int age = 20; } /** * 生产者 * */ class Producer implements Runnable { private Info info = null; Producer(Info info) { this.info = info; } public void run() { boolean flag = false; for (int i = 0; i < 25; ++i) { if (flag) { this.info.set("Rollen", 20); flag = false; } else { this.info.set("ChunGe", 100); flag = true; } } } } /** * 消费者类 * */ class Consumer implements Runnable { private Info info = null; public Consumer(Info info) { this.info = info; } public void run() { for (int i = 0; i < 25; ++i) { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } this.info.get(); } } } /** * 测试类 * */ class hello { public static void main(String[] args) { Info info = new Info(); Producer pro = new Producer(info); Consumer con = new Consumer(info); new Thread(pro).start(); new Thread(con).start(); } }
【运行结果】:
Rollen<===>20
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
Rollen<===>20
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
ChunGe<===>100
从运行结果来看,错乱的问题解决了,现在是Rollen 对应20,ChunGe对于100
,但是还是出现了重复读取的问题,也肯定有重复覆盖的问题。如果想解决这个问题,就需要使用Object类帮忙了、
,我们可以使用其中的等待和唤醒操作。
要完成上面的功能,我们只需要修改Info类饥渴,在其中加上标志位,并且通过判断标志位完成等待和唤醒的操作,代码如下:
class Info { public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public synchronized void set(String name, int age){ if(!flag){ try{ super.wait(); }catch (Exception e) { e.printStackTrace(); } } this.name=name; try{ Thread.sleep(100); }catch (Exception e) { e.printStackTrace(); } this.age=age; flag=false; super.notify(); } public synchronized void get(){ if(flag){ try{ super.wait(); }catch (Exception e) { e.printStackTrace(); } } try{ Thread.sleep(100); }catch (Exception e) { e.printStackTrace(); } System.out.println(this.getName()+"<===>"+this.getAge()); flag=true; super.notify(); } private String name = "Rollen"; private int age = 20; private boolean flag=false; } /** * 生产者 * */ class Producer implements Runnable { private Info info = null; Producer(Info info) { this.info = info; } public void run() { boolean flag = false; for (int i = 0; i < 25; ++i) { if (flag) { this.info.set("Rollen", 20); flag = false; } else { this.info.set("ChunGe", 100); flag = true; } } } } /** * 消费者类 * */ class Consumer implements Runnable { private Info info = null; public Consumer(Info info) { this.info = info; } public void run() { for (int i = 0; i < 25; ++i) { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } this.info.get(); } } } /** * 测试类 * */ class hello { public static void main(String[] args) { Info info = new Info(); Producer pro = new Producer(info); Consumer con = new Consumer(info); new Thread(pro).start(); new Thread(con).start(); } }
【程序运行结果】: Rollen<===>20 ChunGe<===>100 Rollen<===>20 ChunGe<===>100 Rollen<===>20 ChunGe<===>100 Rollen<===>20 ChunGe<===>100 Rollen<===>20 ChunGe<===>100 Rollen<===>20 ChunGe<===>100 Rollen<===>20 ChunGe<===>100 Rollen<===>20 ChunGe<===>100 Rollen<===>20 ChunGe<===>100 Rollen<===>20 ChunGe<===>100 Rollen<===>20 ChunGe<===>100 Rollen<===>20 ChunGe<===>100 Rollen<===>20 先在看结果就可以知道,之前的问题完全解决。
《完》
发表评论
-
java中queue的使用
2012-08-27 10:00 7613Queue接口与List、Set同一级别,都是继承了Colle ... -
多线程sleep,yield,wait区别
2012-08-24 00:04 1268sleep() 1) sleep ()函数有一个参数, ... -
Thread的setDaemon(true)方法的作用
2012-08-23 23:34 3444定义:守护线程--也称“服务线程”,在没有用户线程可服务时会自 ... -
InterruptedException的解读
2012-08-23 22:06 1807最近写了些多线程的程序,用Thread.sleep()的时候有 ... -
Java创建线程的两个方法
2012-08-14 16:53 1140Java提供了线程类Thread来创建多线程的程序。其实,创建 ...
相关推荐
【JAVA多线程总结】 Java 多线程是Java编程中的关键特性,它允许程序同时执行多个任务,提高系统的效率和响应性。本篇总结涵盖了Java多线程的基础概念、创建与启动、线程调度、同步与协作以及新特性。 **一、Java...
Java多线程是Java编程语言中的一个重要特性,它允许开发者创建并发执行的多个线程,从而提高程序的执行效率和响应速度。Java中实现多线程主要有两种方式:继承Thread类和实现Runnable接口。 ### 继承Thread类 在...
配合`JAVA多线程总结.ppt`,你可以得到一个更直观和简洁的概览,快速回顾和掌握上述关键知识点。虽然中文版翻译可能存在不足,但原版英文书籍通常能更准确地传达作者的意图和细节,值得深入阅读。
Java多线程是Java编程语言中一个非常重要的概念,它允许开发者在一个程序中创建多个执行线程并行运行,以提高程序的执行效率和响应速度。在Java中,线程的生命周期包含五个基本状态,分别是新建状态(New)、就绪...
Java多线程是指在Java语言中同时运行多个线程,从而实现对任务的并行处理。这是Java中一个非常重要的概念和技能,尤其在需要高并发处理和优化性能的场景中显得尤为重要。以下将详细梳理Java多线程编程中的一些关键...
Java多线程是Java编程语言中的一个重要特性,它允许在单个程序中同时执行多个代码路径,从而提高程序的效率和响应性。在Java中,线程生命周期包括六种状态:新建状态(NEW)、可运行状态(RUNNABLE)、休眠状态...
Java多线程是Java编程中的一个核心概念,它在现代软件开发中扮演着至关重要的角色。多线程允许程序同时执行多个任务,提高了系统资源的利用率,提升了应用程序的响应速度和并发性能。对于大型分布式系统、Web应用...
java多线程思维导图总结【超详细,可下载】
### Java多线程编程总结 #### 一、Java线程:概念与原理 1. **操作系统中线程和进程的概念** - 当前的操作系统通常为多任务操作系统,多线程是实现多任务的一种手段。 - **进程**:指内存中运行的应用程序,每个...
### Java多线程编程总结 #### 一、Java线程:概念与原理 - **操作系统中线程和进程的概念** 当前的操作系统通常都是多任务操作系统,多线程是一种实现多任务的方式之一。在操作系统层面,进程指的是内存中运行的...
### Java多线程分页查询知识点详解 #### 一、背景与需求分析 在实际的软件开发过程中,尤其是在处理大量数据时,如何高效地进行数据查询成为了一个关键问题。例如,在一个用户众多的社交平台上,当用户需要查看...
java多线程全面总结,简单的介绍多线程技术中的各种应用问题,是你对多线程有更多的认识!
JAVA 多线程总结 扩展java lang Thread类 实现java lang Runnable接口
总结起来,“JAVA多线程编程技术PDF”涵盖了多线程的基本概念、同步机制、线程通信、死锁避免、线程池以及线程安全的集合类等内容。通过深入学习这份资料,开发者可以全面掌握Java多线程编程技术,提升程序的并发...
总结一下,Java多线程涉及的内容广泛,包括线程的基本概念、创建、状态转换、调度和优先级管理。理解并掌握这些知识点对于编写高效并发的Java程序至关重要,也是面试中必不可少的技术点。在实际编程中,合理利用多...
总结来说,这个实验源码涵盖了Java多线程的基础和应用,包括线程的创建、运行、同步、通信,以及网络编程和数据库操作。通过这些实验,学生可以深入理解Java并发编程的核心概念,并掌握实际开发中的多线程设计技巧。
### Java多线程编程知识点详解 #### 一、引言 在现代软件开发中,多线程编程是一项不可或缺的技术,尤其是在高性能和响应性要求较高的应用中。Java作为一种广泛使用的编程语言,提供了强大的多线程支持。本文将...
Java多线程程序设计是Java开发中的重要组成部分,它允许程序在同一时间执行多个任务,从而提高了系统的效率和响应性。本文将深入探讨Java多线程的相关概念和实现方式。 一、理解多线程 1. **线程定义**:线程是一...