我之前看到书上一个JAVA多线程的例子,我想学过OS的人看见多线程程序后都会有一些冲动,我也是,二话没说就把代码输到Eclipse中看了一下结果,发现和自己想的一样,结果也很漂亮,然后我就写了一篇日志,下面的源代码不是我写的是书上看到的:
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
public class JoinTest extends JFrame
{
private Thread threadA;
private Thread threadB;
final JProgressBar progressBar1 = new JProgressBar();
final JProgressBar progressBar2 = new JProgressBar();
int count = 0;
public static void main(String[] args)
{
init(new JoinTest(), 200, 200);
}
public JoinTest()
{
super();
getContentPane().add(progressBar1, BorderLayout.NORTH);
getContentPane().add(progressBar2, BorderLayout.SOUTH);
progressBar1.setStringPainted(true);
progressBar2.setStringPainted(true);
threadA = new Thread(new Runnable(){
int count = 0;
public void run(){
while (true){
progressBar1.setValue(++count);
try
{
threadA.sleep(100);
threadB.join();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
});
threadA.start();
threadB = new Thread(new Runnable(){
int count = 0;
public void run(){
while (true)
{
progressBar2.setValue(++count);
try
{
threadB.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
if(count == 100)
break;
}
}
});
threadB.start();
}
public static void init(JFrame frame, int width, int height)
{
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(width, height);
frame.setVisible(true);
}
}
源代码的解释我就不在详细写了,就在前面的日志中,上面的程序是用join来实现的,我们知道join()方法是使当前运行线程暂停,直到调用join的线程运行完毕,当前线程才开始执行,这样我们程序跑起来后结果是:下面的进度条先增长,当下面的进度条增长满后,上面的进度条才开始增长。
前几天看见一位好友在网上发的一篇《求助高手》的日志,我不是高手,不过我还是看了一下他的源代码,返现那个源代码很像我的那段,不知道是不是他看完我的日志后自己改写的。那个好友写的代码如下:
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
public class JoinTestT extends JFrame
{
private int i ;
private Thread threadA;
private Thread threadB;
final JProgressBar progressBar1 = new JProgressBar();
final JProgressBar progressBar2 = new JProgressBar();
int count = 0;
public static void main(String[] args)
{
init(new JoinTestT(), 200, 200);
}
public JoinTestT()
{
super();
getContentPane().add(progressBar1, BorderLayout.NORTH);
getContentPane().add(progressBar2, BorderLayout.SOUTH);
progressBar1.setStringPainted(true);
progressBar2.setStringPainted(true);
threadA = new Thread(new Runnable(){
int count = 0;
public void run(){
while (true){
synchronized(this){
progressBar1.setValue(++count);
try
{
threadA.sleep(100);
while(i != 1){
this.wait();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
});
threadA.start();
threadB = new Thread(new Runnable(){
int count = 0;
public void run(){
while (true)
{
synchronized(this){
progressBar2.setValue(++count);
try
{
threadB.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
if(count == 100){
i = 1;
this.notify();
break;
}
}
}
}
});
threadB.start();
}
public static void init(JFrame frame, int width, int height)
{
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(width, height);
frame.setVisible(true);
}
}
这个程序表面上看上去什么问题也没有,不过程序跑起来后和我们预期的结果一样,思想很简单,先让一个线程跑起来,当该线程的时间片结束后,另外一个线程再开始跑,但是该线程要跑起来需要一个条件要满足,这个条件当前不满足,线程死循环判断,当时间片结束后,第二线程又开始了,这样直到第二个线程结束后,把相应的条件设置好后第一个线程才可以跑,这是我们预期的结果,但是程序跑起来后先是下面的进度条在跑,等下面一个进度条跑满后,上面的进度条卡死不动了,这就就是这个程序的问题。我当时看了很长时间,也没有看出来,我目前只是理论上的推测,但是JAVA的多线程程序我是几乎没有自己动手写过,所以当时看了很长时间也没有找到解决方法,今天中午和一位工程师交流一下,他提出了一种解决方法,我先说一下上面程序错误的原因:原因很简单,线程A中的this对象和线程B中的this对象不是同一个对象,那么线程在一个对象上睡觉,我们在另外一个对象去叫醒在前面那个对象睡觉的线程是不可行的。我当初也以为这里的this对象是同一对象,其实都是内部类对象,他们不是指向同一个对象而是指向各自内部类对象,这里有内部类,这个很重要。下面就是一位工程师给出的解决方案,很漂亮:
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
public class JoinTestT extends JFrame
{
private int i ;
private Thread threadA;
private Thread threadB;
final JProgressBar progressBar1 = new JProgressBar();
final JProgressBar progressBar2 = new JProgressBar();
int count = 0;
public static void main(String[] args)
{
init(new JoinTestT(), 200, 200);
}
public JoinTestT()
{
super();
getContentPane().add(progressBar1, BorderLayout.NORTH);
getContentPane().add(progressBar2, BorderLayout.SOUTH);
progressBar1.setStringPainted(true);
progressBar2.setStringPainted(true);
threadA = new Thread(new Runnable(){
int count = 0;
public void run(){
while (true){
synchronized(JoinTestT.this){
progressBar1.setValue(++count);
try
{
threadA.sleep(100);
while(i != 1){
JoinTestT.this.wait();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
});
threadA.start();
threadB = new Thread(new Runnable(){
int count = 0;
public void run(){
while (true)
{
synchronized(JoinTestT.this){
progressBar2.setValue(++count);
try
{
threadB.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
if(count == 100){
i = 1;
JoinTestT.this.notify();
break;
}
}
}
}
});
threadB.start();
}
public static void init(JFrame frame, int width, int height)
{
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(width, height);
frame.setVisible(true);
}
}
这时候程序跑起来的结果和之前的那段程序跑起来的结果完全一样。我当时看见这位好友写的代码后感触很多,对于程序这东西,我们不能一味的敲别人的代码,那样我们就是充其量是一个高级打字工。别人的程序是要看,但是我相信很多人在看别人的程序的时候会有很多想法,这时候just make it,这句话很重要,我们的想法或许是错的,但是我们会学到很多东西。我也是JAVA的学习者,爱好者,以我目前的实力根本不可能驾驭博大精深的JAVA,所以我还需要跟多的努力,虽然基础好,但是要想学好JAVA也不见的很容易,我也非常感谢这位好友的写的这段代码,使得我学到了一些自己不会的东西,希望你能更上一层楼,期待以后更多的交流。