开篇说明,有点基础,知道Thread,Runnable如何使用和两者之间的关系的可以直接跳过。
先说说Thread和Runnable之间的关系,简单到不想多说一句话,看下面代码:
public class Thread implements Runnable {
...省略,详细自行查看源代码...
}
看到以上代码,应该明白了吧。不明白可以看一下总结:Thread类实现Runnable接口,创建一个线程的时候可以使用继承Thread的方式,但是注意Java是单继承的,当你继承了Thread你就无法进行其它继承了。所以,可以也实现Runnable接口的方式,这样就可以继承其他类也同时可以实现线程创建。
下面先简单介绍Thread
//使用继承Thread的方式,创建一个线程类
public class OneThread extends Thread{
@Override
public void run(){
super.run();
System.out.println("one thread!!!!");
}
}
//再建一个测试类
public class TestThread {
public static void main(String[] args) {
OneThread oneThread = new OneThread();
oneThread.start();
System.out.println("完成!");
}
}
注意到运行结果没有?系统可能先打印“完成!”,再打印“one thread!!!!”,按照平时写单线程来说,应该是先打印“one thread!!!!”才对吧。不过这里是多线程,OneThread类创建了一个线程,这个线程里面打印“one thread!!!!”,而打印“完成!”是在主线程上完成的。这也就说明了,使用多线程之后,代码运行结果跟调用顺序是无关的。(“one thread!!!!”这串字符串也有可能先出现,反正你理解上面这话就行了)
下面在对以上两个类进行一下改造,模拟一下cpu执行哪个线程是具有不确定性的。
public class OneThread extends Thread{
@Override
public void run(){
try {
for (int i = 0; i < 10; i++) {
int sleepTime = (int) (Math.random()*1000);
Thread.sleep(sleepTime);
System.out.println("one thread!!!!");
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
public class TestThread {
public static void main(String[] args) {
try {
OneThread oneThread = new OneThread();
oneThread.start();
for (int i = 0; i < 10; i++) {
int sleepTime = (int) (Math.random()*1000);
Thread.sleep(sleepTime);
System.out.println("完成!");
}
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
使用一个随机数,生成一个随机的挂起时间。从而可以更好地观察cpu选择执行哪个现场的不确定性。通俗点说一下线程开始执行,假如cpu选择了主线程,然后主线程睡觉1秒钟,那么在这一秒钟cpu可能就会选择其它线程去执行,而不会傻X那样在等主线程,所以此时就会去执行了其它线程。大概这样,不理解可以留言说一下。
上面说了那么多顺序的问题。反正一句话说到尾,多线程来说,执行顺序是不确定的。还有,线程的启动顺序跟执行start()方法的顺序也没什么关系的。start()执行的顺序不代表线程的启动顺序。在来两段代码爽爽呗!!!继续捣鼓那两个类吧。。。懒,新建一个类都不想。
public class OneThread extends Thread{
private int i;
//写个带参数的构造方法,主要用来看顺序的
public OneThread(int i){
super();
this.i = i;
}
@Override
public void run(){
System.out.println(i);
}
}
public class TestThread {
public static void main(String[] args) {
//如各位所见,下面的start()我按顺序排好的。
OneThread o1 = new OneThread(1);
OneThread o2 = new OneThread(2);
OneThread o3 = new OneThread(3);
OneThread o4 = new OneThread(4);
OneThread o5 = new OneThread(5);
OneThread o6 = new OneThread(6);
o1.start();
o2.start();
o3.start();
o4.start();
o5.start();
o6.start();
}
}
运行结果,绝对不是123456,如果是,那么恭喜你,运气挺好的。无聊话说太多了。意思基本懂吧。这些都很简单,甚至有些人看了会不自觉地发出,哼一声。
Thread的简单介绍说到这里,后面还有Runnable的简单介绍。
通过实现Runnable接口来实现多线程,不废话,先上一张图,看看Thread类的构造方法,我们上面那些用的基本都是无参的构造方法,如下图,第二个,就是我们即将要用到的构造方法:
//创建一个类,实现Runnable接口。
public class OneRunnable implements Runnable {
@Override
public void run() {
System.out.println("one runnable!!!");
}
}
public class TestThread {
public static void main(String[] args) {
//
Runnable runnable = new OneRunnable();
//这里就是用到了上图的第二个构造方法,不用多说吧,就这样
Thread thread = new Thread(runnable);
thread.start();
System.out.println("完成");
}
}
直接实现Runnable接口这样解决了Java单继承这一尴尬!!!!
后面应该先简单一起学习下共享数据和Thread的几个方法。
向大家推荐eclipse的vim插件,太好用了。
这里不是广告,推荐本书《Java多线程核心技术》-高洪岩,因为我是看着这本书学习的。上面的文章是学习笔记,并不是用来说教的,不要错了点什么就喷我。