Java中的多线程(学习笔记)
Java的多线程,下面是我做的笔记,仅供参考和复习。
- java的多线程:同时执行多个程序区块
- 启动线程:必须具备两个条件:
(1) 此类必须是延伸自Thread类,使自己成为它的子类
(2) 线程的处理必须编写在run()方法中
注:Thread类存放在java.lang类库中,所以无需手动加载,调用start(),用以启动线程
3.实现Runnable接口来创建线程
由于Java不能多重继承,Java提供了Runnable接口,恰好可以解决这个难题。接口中声明run()方法,只要在类中确实定义run()方法,就可以创建线程了。
下面是例子:
public class MyRunnable implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName());
//得到当前thread对象 然后在调用这个thread的 getName()方法。
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
MyRunnable t1=new MyRunnable();
MyRunnable t2=new MyRunnable();
Thread th1=new Thread(t1,”MyThread1″);
Thread th2=new Thread(t2,”MyThread2″);
th1.start();
th2.start();
}
}
4.线程的管理
每一个线程,在其创建和死亡之前,均会处于四种状态之一:新建的(newly created)、可运行的(runnable)、被冻结的(blocked)与死亡的(dead);
当用new Thread()创建对象时,线程所处的便是这种状态,但此时系统并不会配置资源,直到用start()方法启动线程时才会配置;
当start()启动线程时,线程便进入可运行的状态,谁先抢到cpu,谁开始执行run()方法,其余的线程便在队列中等待机会争取cpu资源;
当线程调用对象的wait() method 或该线程本身调用sleep(),冻结状态线程便产生。sleep(long millis)可用来设定睡眠的时间,millis毫秒(1/1000秒)。该线程和另一个线程join()在一起,则其他未启动的线程或程序代码会等到该线程结束后才会开始执行;
当线程被冻结时,便停止run()的执行,直到被冻结的因素消失,线程便回到可运行状态;
被冻结因素消失的原因可以是:
a,如果线程是用调用对象的wait()所冻结,则改对象的notify() 被调用时可解除冻结。(notify:告知);
b,线程进入睡眠状态,但指定的时间到了。
当线程的run()执行结束,或调用了stop(),则线程进入死亡状态。
举例:
1.如果要简单的设计线程的排序,可用join(),当某一线程调用join时,则其他线程会等到该线程结束后才开始执行,下面的例子,使得dog线程先完成后,再执行cat线程,等到线程执行结束后,再打印“Hello world”;
//CTest.java public class CTest extends Thread { private String id; public CTest(String str) { id=str; } public void run() { for ( int i= 0 ;i< 4 ;i++) { try { sleep(( int )( 1000 *Math.random())); } catch (InterruptedException e) {} System.out.println(id+ "is running.." ); } } } //App2.java public class App2 { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub CTest dog= new CTest( "doggy" ); CTest cat= new CTest( "cat" ); dog.start(); //启动dog线程 try { dog.join(); //限制dog线程结束后才能往下执行 cat.start(); //启动cat线程 cat.join(); //限制cat线程结束后才能往下执行 } catch (InterruptedException e) {} System.out.println( "Hello World" ); } } |
有没有注意到try…catch这段代码?这是因为,sleep()和join()必须写在try…catch里面,以捕捉可能出现的异常。
再来讲一下关于同步处理,先来举个例子: 假设有家银行,它可接受顾客的汇款,每做一次汇款,便可计算出汇款的总额,现在又两名顾客,每人分3次,每次100元将钱导入,最后银行汇款的总额应该为600元。
为解决这个问题,我们来写段代码:
//CBank.java public class CBank { private static int sum= 0 ; public static void add( int n) { int tmp=sum; tmp=tmp+n; try { Thread.sleep(( int )( 1000 *Math.random())); } catch (InterruptedException e) {} sum=tmp; System.out.println( "sum=" +sum); } } //CCustomer.java public class CCustomer extends Thread { //顾客类,继承自Thread类 public void run() { for ( int i= 1 ;i<= 3 ;i++) CBank.add( 100 ); //将100元分3次导入 } } //App3.java public class App3 { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub CCustomer c1= new CCustomer(); CCustomer c2= new CCustomer(); c1.start(); c2.start(); } }<br><br><br> //运行结果<br>sum=100<br>sum=200<br>sum=100<br>sum=300<br>sum=200<br>sum=300 |
运行结果与我们预想的600不一样。这是因为两个线程共享同一个变量,且其中一个线程在run()还没结束前,另一个线程已经开始启动了,因此造成计算上的错误。
要得到600,只要让第一个线程吹了完毕,接着再处理第二个线程即可,这就要用到同步处理了,即synchronized,在add()之前加上这个关键字,可以使得各线程在时间上取得协调,一次只允许一个线程进入run()进行处理,代码如下:
//CBank.java public class CBank { private static int sum= 0 ; public synchronized static void add( int n) { int tmp=sum; tmp=tmp+n; try { Thread.sleep(( int )( 1000 *Math.random())); } catch (InterruptedException e) {} sum=tmp; System.out.println( "sum=" +sum); } } //CCustomer.java public class CCustomer extends Thread { //顾客类,继承自Thread类 public void run() { for ( int i= 1 ;i<= 3 ;i++) CBank.add( 100 ); //将100元分3次导入 } } //App3.java public class App3 { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub CCustomer c1= new CCustomer(); CCustomer c2= new CCustomer(); c1.start(); c2.start(); } }<br>运行结果:<br>sum= 100 <br>sum= 200 <br>sum= 300 <br>sum= 400 <br>sum= 500 <br>sum= 600 |
至此,多线程的学习暂时到这里。。