1.2-使用多线程
1.2.1 继承Thread类的方式使用多线程
/* * 使用多线程 */ public class t1 { public static void main(String[] args) { MyThread mythread = new MyThread(); mythread.start(); System.out.println("运行结束!"); } } /* * 使用继承Thread类的方式使用多线程 */ class MyThread extends Thread{ @Override public void run() { super.run(); System.out.println("MyThread"); } }
控制台结果:
运行结束! MyThread
从实验结果看,当使用了多线程时,代码的运行结果和与代码的执行顺序无关。因为线程是一个子任务,CPU以随机的时间来调用线程中的run方法(实际上是start()方法通知“线程规划器”,此线程已经准备就绪,等待调用线程对象run()方法),具有异步执行的效果。
/* * 使用多线程 */ public class t1 { public static void main(String[] args) { MyThread mythread = new MyThread(1); MyThread mythread1 = new MyThread(2); MyThread mythread2 = new MyThread(3); MyThread mythread3 = new MyThread(4); MyThread mythread4 = new MyThread(5); MyThread mythread5 = new MyThread(6); mythread.start(); mythread1.start(); mythread2.start(); mythread3.start(); mythread4.start(); mythread5.start(); } } /* * 使用继承Thread类的方式使用多线程 */ class MyThread extends Thread{ private int i; public MyThread(int i) { super(); this.i = i; } @Override public void run() { System.out.println(i); } }
1 6 5 4 3 2
多线程的异步性
public class t2 { public static void main(String[] args) { MyRunnable runnable = new MyRunnable(); //创建一个Runnbale接口的对象 Thread thread = new Thread(runnable); //创建一个线程,观察下图中的2、3构造方法,参数为Runnable接口,说明构造函数支持传入一个Runnable接口的对象 thread.start(); System.out.println("运行结束!"); } } /* * 实现Runnable接口的方式使用多线程 */ class MyRunnable implements Runnable{ @Override public void run() { System.out.println("运行中!"); } }
运行结束! 运行中!
另外说明,Thread.java类也实现了Runnable接口,所以构造函数Thread(Runnable target)也能传入一个Thread类的对象。
比较两种实现多线程的方式
- 继承Thread类,线程代码存放在Thread子类的run()方法中,重写了父类Thread的run方法。
- 实现Runnable接口:线程代码存放在实现接口的子类的run()方法中,实现了Runnable接口的run方法。
- Java语言的特点是单继承,那么继承Thread类的方式创建新线程时,就不能支持多继承。为了支持多继承,我们可以实现Runnable的方式,一边实现一边继承
1.2.2
package JavaMultiThread; /* * a、b、c、d、e指向的是同一个MyThread对象,所以会出现对同一个资源的访问 */ public class t1 { public static void main(String[] args) { MyThread mythread = new MyThread(); Thread a = new Thread(mythread, "A"); Thread b = new Thread(mythread, "B"); Thread c = new Thread(mythread, "C"); Thread d = new Thread(mythread, "D"); Thread e = new Thread(mythread, "E"); a.start(); b.start(); c.start(); d.start(); e.start(); } } class MyThread extends Thread{ private int count = 5; @Override public void run() { super.run(); count--; System.out.println("由" + Thread.currentThread().getName() + " 计算 count= " + count); } }
由A 计算 count= 3 由E 计算 count= 0 由D 计算 count= 0 由C 计算 count= 2 由B 计算 count= 3
package JavaMultiThread; /* * a、b、c、d、e指向的是同一个MyThread对象,所以会出现对同一个资源的访问,但是出现了非线程安全的问题 */ public class t1 { public static void main(String[] args) { MyThread mythread = new MyThread(); Thread a = new Thread(mythread, "A"); Thread b = new Thread(mythread, "B"); Thread c = new Thread(mythread, "C"); Thread d = new Thread(mythread, "D"); Thread e = new Thread(mythread, "E"); a.start(); b.start(); c.start(); d.start(); e.start(); } } class MyThread extends Thread{ private int count = 5; @Override public synchronized void run() { //使用同步锁synchronized super.run(); count--; System.out.println("由" + Thread.currentThread().getName() + " 计算 count= " + count); } }
由A 计算 count= 4 由E 计算 count= 3 由D 计算 count= 2 由C 计算 count= 1 由B 计算 count= 0
说明synchronized关键字:当多个线程在执行run方法时,首先要判断run方法有没有上锁,如果上锁说明有其他的线程正在调用run方法,那么必须等其他线程对run方法调用结束后,才可以执行run方法。这样就可以实现排队对count变量的值减1的效果。
最后在强调一下:当一个线程想要执行临界区内的代码时,线程首先尝试去拿这把锁,如果能拿到,就可以执行sunchronized方法中的代码。如果不能拿到这把锁,那么这个线程会不断地尝试去拿这把锁,直到能拿到为止。但是会有多个线程会同事去拿这把锁。
再说一下非线程安全:它指多个线程对同一个对象中的同一个实例变量进行操作时会出现值被更改、值不同步的情况,进而影响程序的执行流程。
1.2.3
Thread.currentThread().getName()和this.getName()
package JavaMultiThread; public class t1 { public static void main(String[] args) { MyThread mythread = new MyThread(); Thread t = new Thread(mythread); t.setName("进程1"); t.start(); } } class MyThread extends Thread{ public MyThread() { System.out.println("MyThread----begin"); System.out.println("Thread.currentThread().getName() = " + this.currentThread().getName()); System.out.println("this.getName()=" + this.getName()); System.out.println("MyThread----end"); } @Override public void run() { System.out.println("run----begin"); System.out.println("Thread.currentThread().getName() = " + this.currentThread().getName()); System.out.println("this.getName()=" + this.getName()); System.out.println("run----end"); } }
MyThread----begin Thread.currentThread().getName() = main this.getName()=Thread-0 MyThread----end run----begin Thread.currentThread().getName() = 进程1 this.getName()=Thread-0 run----end
这里currentThread()方法可返回代码段正在被哪个线程调用的信息,而this表示的是当前对象。
MyThread mythread = new MyThread();
调用MyThread的构造方法,Thread.currentThread().getName()是获得调用这个方法的线程的名字,在main线程中调用的当然是main了,而this.getName()这个方法是获取当前MyThread对象的名字,只是单纯的方法的调用。因为子类MyThread没有重写这个方法,所以调用的是父类Thread中的方法getName()方法。
this.getName()-->
public final String getName() { return String.valueOf(name); }
//最后要输出name的值,而你在MyThread的构造方法中会默认调用父类默认无参的public Thread()
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
-->最后输出的name就是这个"Thread-" + nextThreadNum()
private static synchronized int nextThreadNum() { return threadInitNumber++; }
-->private static int threadInitNumber;因为是第一次调用nextThreadNum() 方法所以返回值为0
-->this.getName()=Thread-0
Thread t = new Thread(mythread);
MyThread的对象作为参数传递给Thread的构造函数,。首先要明白mythread和t是两个完全不同的类,他俩之间唯一的联系就是。
/*Thread类重写了Runnable接口的run()方法。 该run()方法首先判断当前是否有Runnable的实现target存在。 如果存在就执行target.run() */ @Override public void run() { if (target != null) { target.run(); } }
实际上new Thread(mythread)相当于将myThread线程委托给t去执行,mythread作为一个target传递给了t。从上述源码看出t.run()被调用的时候,它会调用target.run()方法,也就是说它是直接调用mythread对象的run方法。在run方法被执行的时候,this.getName()实际上返回的是target.getName(),即为Thread-0。还不清楚看下面
public static void main(String[] args) { MyThread mythread = new MyThread(); mythread.setName("Hello"); //我把mythread对象的名字改了 Thread t = new Thread(mythread); //System.out.println("main begin t isAlive = " + t.isAlive()); t.setName("进程1"); t.start(); //System.out.println("main end t isAlive = " + t.isAlive()); }
MyThread----begin Thread.currentThread().getName() = main this.getName()=Thread-0 MyThread----end run----begin Thread.currentThread().getName() = 进程1 this.getName()=Hello run----end
1.2.4
isAlive()用来判断当前线程是否属于活动状态:活动状态就是指线程处于正在运行或开始准备运行的状态
public class t1 { public static void main(String[] args) { MyThread mythread = new MyThread(); //mythread.setName("Hello"); Thread t = new Thread(mythread); System.out.println("main begin t isAlive = " + t.isAlive()); t.setName("进程1"); t.start(); System.out.println("main end t isAlive = " + t.isAlive()); } } class MyThread extends Thread{ public MyThread() { System.out.println("MyThread----begin"); System.out.println("Thread.currentThread().getName() = " + this.currentThread().getName()); System.out.println("Thread.currentThread().isAlive() = " + this.currentThread().isAlive()); System.out.println("this.getName()=" + this.getName()); System.out.println("this.isAlive()=" + this.isAlive()); System.out.println("MyThread----end"); } @Override public void run() { System.out.println("run----begin"); System.out.println("Thread.currentThread().getName() = " + this.currentThread().getName()); System.out.println("Thread.currentThread().isAlive() = " + this.currentThread().isAlive()); System.out.println("this.getName()=" + this.getName()); System.out.println("this.isAlive()=" + this.isAlive()); System.out.println("run----end"); } }
MyThread----begin Thread.currentThread().getName() = main Thread.currentThread().isAlive() = true this.getName()=Thread-0 this.isAlive()=false MyThread----end main begin t isAlive = false main end t isAlive = true run----begin Thread.currentThread().getName() = 进程1 Thread.currentThread().isAlive() = true this.getName()=Thread-0 this.isAlive()=false run----end
1.2.5
sleep():该方法的作用是在指定的毫秒数内让当前“正在执行的线程”暂停执行,而这个正在执行的线程就是Thread.currentThread()
getId():取得线程的唯一标识
作者:Ryanjie
出处:http://www.cnblogs.com/ryanjan/
本文版权归作者和博客园所有,欢迎转载。转载请在留言板处留言给我,且在文章标明原文链接,谢谢!
如果您觉得本篇博文对您有所收获,觉得我还算用心,请点击右下角的 [推荐],谢谢!