java 多线程
2017-09-02 21:52 雄风狂飙 阅读(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
执行多次都是一个结果。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架