代码改变世界

java 多线程

  雄风狂飙  阅读(207)  评论(0编辑  收藏  举报

最近工作上有个地方需要用到多线程,是用C++的,下午加班改代码,但是网络出现问题,连不了主机,于是在java上面测试并回顾了一些知识。记录一下。

1.多线程的类helloworld。

在thread类中持有一个实现了runnable接口的实例化对象,然后thread类run的时候,会调用runnable的run。这一点在很多入门的书籍中都有介绍,没必要赘述,但是为什么要这么写,这里稍微把java中的代码粘贴一下。代码如下:

Thread类有一个接受runnable实现对象的构造函数,

1
2
3
public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
    }

  init函数中最重要的一段代码是:this.target = target;

即给Thread的target这个变量set成了传进来的target。当Thread的run执行的时候,实际上会调用target的run函数。在源码中是这么说的“/**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.”

也就是Thread的start执行以后调用Thread的run方法。而run方法会调用target的run方法,代码如下:

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

  测试的Thread主类如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class TestThread {
     
    static int threadNum = 10;
    static int maxloop = 10000;
     
    public static void main(String arg[])
    {
        Thread threads[] = new Thread[100];
 
        for( int i = 0; i <= threadNum ; ++i)
        {
            String threadName = "Thread " + Integer.valueOf(i);
            threads[i] = new Thread(new TestRunable(threadName,maxloop));
            threads[i].start();
        }
         
        for( int i = 0; i <= threadNum ; ++i)
        {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
             
            System.out.println(Integer.valueOf(i) + "thread done.");
             
        }
        System.out.println( "count==" + Integer.valueOf( Global.count ) );
         
    }
}

  这里用到了一个全局变量Global.count,其目的在下面第三点说明。

2.测试join函数。join函数就是等待自身的函数,其效果如下:

8thread done.

。。。

Thread 9  9999
Thread 9  10000
9thread done.
10thread done.

也就是在线程8结束以后,线程9还未结束,那么主线程就一直等待线程9结束以后,再等待线程10结束,然后再继续往下执行。

3.测试线程操作统一个未上锁的变量的情况。

这里先把实现了runnable接口的类也贴出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package test;
 
public class TestRunable implements Runnable {
     
    private
        int mi;
        String ms;
        int mmaxloop;
     
    @Override
    public void run() {
        // TODO Auto-generated method stub
         
         
        for( int i = 0;i<=mmaxloop*10;++i  )
        {
            System.out.println( ms + "  " + Integer.valueOf(mi));
            ++mi;
            ++Global.count;
        }
    }
     
    TestRunable(String ss,int maxLoop)
    {
        this.mi = 0;   
        this.ms = ss;
        mmaxloop = maxLoop;
    }
}

  此外,还有全局变量的类也一道贴出来:

1
2
3
4
public class Global {
    public
    static int count = 0;
}

  其结果是每次测试的结果,对全局变量的打印数字都不一致。

比如,某次执行的结果是(对源码中的某些数字可能进行一些放大或者缩小,不影响其效果): 

7thread done.
8thread done.
9thread done.
10thread done.
count==1100010

另外一次执行的结果是:

7thread done.
8thread done.
9thread done.
10thread done.
count==1100011

4.互斥实现。

 testRunnable类的代码修改为:

1
2
3
4
5
6
7
8
9
for( int i = 0;i<=mmaxloop*100;++i  )
        {
            System.out.println( ms + "  " + Integer.valueOf(mi));
            ++mi;
            synchronized(this)
            {
                ++Global.count;
            }
        }

  再执行多次,查看Global.count结果,都是一个值吗?

第一次:

count==1100009

第二次:

8thread done.
9thread done.
10thread done.
count==1100011

于是,发现根本就没有完成互斥。

5.原来互斥是需要针对一个对象的。经过修改以后的代码如下,就可以完成互斥了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
static int threadNum = 10;
    static int maxloop = 1000;
     
    public static void main(String arg[]) {
        Thread threads[] = new Thread[100];
        System.out.println("ssssssssssss");
        Global global = new Global();
        String threadName = "same";
        TestRunnable testRunnable = new TestRunnable(threadName, maxloop,
                global);
        for (int i = 0; i <= threadNum; ++i) {
            // String threadName = "Thread " + Integer.valueOf(i);
            threads[i] = new Thread(testRunnable);
            threads[i].start();
        }
 
        for (int i = 0; i <= threadNum; ++i) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
 
            // System.out.println(Integer.valueOf(i) + "thread done. mi==" +
            // Integer.valueOf(threads[i].g));
 
            System.out.println(Integer.valueOf(i)
                    + "thread done. global.count=="
                    + Integer.valueOf(global.count));
 
        }
        System.out.println("count==" + Integer.valueOf(global.count));
 
    }

  results:

count==1100000

执行多次都是一个结果。

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示