编写具有多线程程序经常会用到的方法:run(), start(), wait(), notify(), notifyAll(), sleep(), yield(), join()
还有一个关键字:synchronized
下面主要来讲讲:
线程的创建方式就不需要细说,就2种方式 Thread和Runnable
1.run()和start()
实例1:
public class ThreadTest extends Thread { public void run() { for (int i = 0; i < 10; i++) { System.out.print(" " + i); } } public static void main(String[] args) { new ThreadTest().start(); new ThreadTest().start(); } }
这是一个简单的多线程例子
实例2:
public class ThreadTest implements Runnable { public synchronized void run() { for (int i = 0; i < 10; i++) { System.out.print(" " + i); } } public static void main(String[] args) { Runnable r1 = new ThreadTest(); Runnable r2 = new ThreadTest(); Thread t1 = new Thread(r1); Thread t2 = new Thread(r2); t1.start(); t2.start(); } }
在这个例子中,run被加上了synchronized,这个程序输出的结果是什么呢?t1和t2是2个对象的线程,不同对象的线程是不同的,所以在这个程序中synchronized 并没有起到作用,对于synchronized的定义来说,是针对同一对象的多个线程来说的,在某一时刻只有一个线程能访问此对象的数据
实例3:
public class ThreadTest implements Runnable { public synchronized void run() { for (int i = 0; i < 10; i++) { System.out.print(" " + i); } } public static void main(String[] args) { Runnable r = new ThreadTest(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); t2.start(); } }
实例4:
public class ThreadTest implements Runnable { public void run() { synchronized (this) { for (int i = 0; i < 10; i++) { System.out.print(" " + i); } } } public static void main(String[] args) { Runnable r = new ThreadTest(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); t2.start(); } }
实例3和4中,synchronized控制了线程对象的数据共享,输出的结果只能是0123456789,3和4其实区别就是synchronized作用范围
实例5:
public class ThreadTest implements Runnable { public void run() { for (int k = 0; k < 5; k++) { System.out.println(Thread.currentThread().getName() + " : for loop : " + k); } synchronized (this) { for (int k = 0; k < 5; k++) { System.out.println(Thread.currentThread().getName() + " : synchronized for loop : " + k); } } } public static void main(String[] args) { Runnable r = new ThreadTest(); Thread t1 = new Thread(r, "t1_name"); Thread t2 = new Thread(r, "t2_name"); t1.start(); t2.start(); } }
输出结果是:
t1_name : for loop : 0
t1_name : for loop : 1
t1_name : for loop : 2
t2_name : for loop : 0
t1_name : for loop : 3
t2_name : for loop : 1
t1_name : for loop : 4
t2_name : for loop : 2
t1_name : synchronized for loop : 0
t2_name : for loop : 3
t1_name : synchronized for loop : 1
t2_name : for loop : 4
t1_name : synchronized for loop : 2
t1_name : synchronized for loop : 3
t1_name : synchronized for loop : 4
t2_name : synchronized for loop : 0
t2_name : synchronized for loop : 1
t2_name : synchronized for loop : 2
t2_name : synchronized for loop : 3
t2_name : synchronized for loop : 4
第一个for循环没有收synchronized保护,所以t1,t2的执行方式是交错的,第二个循环受synchronized保护,所以结果是有规律的
2.sleep()方法:
实例6:
public class ThreadTest implements Runnable {
public void run() {
for (int k = 0; k < 5; k++) {
if (k == 2) {
try {
Thread.currentThread().sleep(5000);
}
catch (Exception e) {}
}
System.out.println(Thread.currentThread().getName()+ " : " + k);
}
}
public static void main(String[] args) {
Runnable r = new ThreadTest();
Thread t1 = new Thread(r, "t1_name");
Thread t2 = new Thread(r, "t2_name");
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}
}
输出结果:
t1_name : 0
t1_name : 1
t2_name : 0
t2_name : 1
t1_name : 2
t1_name : 3
t1_name : 4
t2_name : 2
t2_name : 3
t2_name : 4
t1被设置了最高的优先级,t2被设置了最低的优先级,t1不执行完,t2就没有机会执行。但由于t1在执行的中途休息了5秒中,这使得t2就有机会执行了。
3.join()方法:主要是让调用改方法的thread完成run方法里面的东西后, 在执行join()方法后面的代码
实例7:
public class ThreadTest implements Runnable { public static int a = 0; public void run() { for (int k = 0; k < 5; k++) { a = a + 1; } } public static void main(String[] args) { Runnable r = new ThreadTest(); Thread t = new Thread(r); t.start(); System.out.println(a); } }
实例8:
public class ThreadTest implements Runnable { public static int a = 0; public void run() { for (int k = 0; k < 5; k++) { a = a + 1; } public static void main(String[] args) throws Exception { Runnable r = new ThreadTest(); Thread t = new Thread(r); t.start(); t.join(); System.out.println(a); } }
实例7和8区别就在于加了个join方法,join能保证调用此方法的线程对象完成对应run方法中的内容,所以实例7来说,不确定输出的是什么,而实例8肯定输出的是5
4.yield()方法:
yield() 方法与sleep() 方法相似,只是它不能由用户指定线程暂停多长时间。按照SUN的说法:sleep方法可以使低优先级的线程得到执行的机会,当然也可以让同优先级和高优先级的线程有执行的机会。而yield()方法只能使同优先级的线程有执行的机会。
实例9:
public class ThreadTest implements Runnable { public void run() { 8 for (int k = 0; k < 5; k++) { if (k == 5 && Thread.currentThread().getName().equals("t1")) { Thread.yield(); } System.out.println(Thread.currentThread().getName() + " : " + k); } } public static void main(String[] args) { Runnable r = new ThreadTest(); Thread t1 = new Thread(r, "t1"); Thread t2 = new Thread(r, "t2"); t1.setPriority(Thread.MAX_PRIORITY); t2.setPriority(Thread.MIN_PRIORITY); t1.start(); t2.start(); } }
输出结果:
t1 : 0
t1 : 1
t1 : 2
t1 : 3
t1 : 4
t2 : 0
t2 : 1
t2 : 2
t2 : 3
t2 : 4
从输出结果上看,yield() 方法不会使不同优先级的线程有执行的机会。本例中t1和t2不同的优先级,在t1被yield的时候,t2也是一点机会也没有,只有等到高优先级t1执行完成之后才有执行的机会,而sleep并不是,可以看看实例6
5.wait(),notify(),notifyAll()
首先说明:wait(), notify(),notifyAll()
这些方法由java.lang.Object类提供,而上面讲到的方法都是由java.lang.Thread类提供(Thread类实现了Runnable接口)。
这三个方法用于协调多个线程对共享数据的存取,所以这三个方法只能在synchronized中使用
实例10:
public class ThreadTest implements Runnable { public static int shareVar = 0; public synchronized void run() { if (shareVar == 0) { for (int i = 0; i < 10; i++) { shareVar++; if (shareVar == 5) { try { this.wait(); } catch (Exception e) {} } } } if (shareVar != 0) { System.out.print(Thread.currentThread().getName()); System.out.println(" shareVar = " + shareVar); this.notify(); } } public static void main(String[] args) { Runnable r = new ThreadTest(); Thread t1 = new Thread(r, "t1"); Thread t2 = new Thread(r, "t2"); t1.start(); t2.start(); } }
输出结果:
t2 shareVar = 5
t1 shareVar = 10
过程:t1线程最先执行。由于初始状态下shareVar为0,t1将使shareVar连续加1,当shareVar的值为5时,t1调用wait() 方法,
t1将处于休息状态,同时释放锁标志。这时t2得到了锁标志开始执行,shareVar的值已经变为5,所以t2直接输出shareVar的值,
然后再调用notify()
方法唤醒t1。t1接着上次休息前的进度继续执行,把shareVar的值一直加到10,由于此刻shareVar的值不为0,
所以t1将输出此刻shareVar的值,然后再调用notify()
方法,由于此刻已经没有等待锁标志的线程,所以此调用语句不起任何作用。