一个线程是进程中的执行流程,一个进程可以同时包括多个线程,每个线程可以得到一段程序的执行时间,这样一个进程就可以具有多个并发执行的线程。
进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)
线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)
2、实现线程的两种方式
2.1、继承Thread类
Thread类是java.lang包中的一个类。
通过该方法实现进程有三个步骤
1)继承Thread类
2)实现run()方法
3)调用start()方法
package com.pjf.thread; //继承Thread类 public class ThreadTest extends Thread { private int count = 10; // 重写run()方法 public void run() { while (true) { System.out.println(count + " "); if (--count == 0) { return; } } } public static void main(String[] args) { ThreadTest threadTest = new ThreadTest(); // 调用start()方法 threadTest.start(); } }
2.2、实现runnable接口
通过该方法实现进程有四个步骤
1)实现Runnable接口
2)重写run方法
3)通过public Thread(Runnable r)构造方法来创建进程
4)调用start()方法
package com.pjf.runnable; //实现Runnable接口 public class RunnableTest implements Runnable { private int count = 10; // 重写run方法 public void run() { while (true) { System.out.println(count + " "); if (--count == 0) return; } } public static void main(String[] args) { // 通过public Thread(Runnable r)构造方法来创建进程 RunnableTest runnableTest = new RunnableTest(); Thread thread = new Thread(runnableTest); // 调用start方法 thread.start(); } }
3、线程的生命周期
线程具有生命周期,包括七个状态,分别为初始状态、就绪状态、运行状态、锁池状态、等待状态、阻塞状态、死亡状态。
初始状态:创建了一个进程对象。
就绪状态:调用了该对象的start()方法。等待获取CPU的使用权就可以运行。
运行状态:获取了CPU,执行程序代码
锁池状态:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
等待状态:调用对象的wait方法,进入等待状态,并释放进程锁。
阻塞状态:调用对象的sleep或join方法,进入休眠状态,休眠结束后,转入就绪状态,等待获取cpu
死亡状态:线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
4、函数说明
sleep();
yeild();
join();
synchronized;
wait();
notify();
notifyAll();
4.1、sleep() 在指定的毫秒数内让当前正在执行的线程休眠
package com.pjf.runnable; public class RunnableTest implements Runnable { private int count = 10; public void run() { while (true) { System.out.println(count + " "); count--; try { // 线程休眠 Thread.sleep((long) (Math.random() * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } if (count == 0) return; } } public static void main(String[] args) { RunnableTest runnableTest = new RunnableTest(); Thread thread = new Thread(runnableTest); thread.start(); } }
4.2、yeild()让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会
package com.pjf.runnable; public class RunnableTestYeild implements Runnable { private int count = 10; public void run() { long beginTime = System.currentTimeMillis(); int count = 0; for (int i = 0; i < 50000000; i++) { count = count + (i + 1); Thread.yield(); } long endTime = System.currentTimeMillis(); System.out.println("用时:" + (endTime - beginTime) + " 毫秒!"); } public static void main(String[] args) { RunnableTestYeild runnableTest = new RunnableTestYeild(); Thread thread = new Thread(runnableTest); thread.start(); } }
4.3、join()主线程等待子线程的终止后才能继续执行
泡茶前必须洗茶杯、烧开水,即使泡茶本身的动作的时间短于烧开水的时间,通过join()实现
package com.pjf.join; public class Water extends Thread { public void run() { System.out.println("开始烧开水"); try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("结束烧开水"); } }
package com.pjf.join; public class WashTeaCup extends Thread { public void run() { System.out.println("开始洗茶杯"); for(int i=0;i<5;i++){ System.out.println("开始洗第"+i+"个茶杯"); try { Thread.sleep(4000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("结束洗第"+i+"个茶杯"); } } }
package com.pjf.join; public class MakeTea extends Thread { private WashTeaCup washTeaCup; private Water water; public MakeTea(WashTeaCup washTeaCup, Water water) { this.washTeaCup = washTeaCup; this.water = water; } public void run() { System.out.println("开始泡茶"); try { washTeaCup.join(); water.join(); Thread.currentThread().sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("泡茶结束"); } public static void main(String[] args) throws InterruptedException { WashTeaCup washTeaCup = new WashTeaCup(); Water water = new Water(); MakeTea makeTea = new MakeTea(washTeaCup, water); makeTea.start(); water.start(); washTeaCup.start(); } }
4.4、synchronized同步和死锁
参考http://www.cnblogs.com/mengdd/archive/2013/02/16/2913806.html,考虑了四种情况,讲解清晰
public class ThreadTest { public static void main(String[] args) { Example example = new Example(); Thread t1 = new Thread1(example); Thread t2 = new Thread1(example); t1.start(); t2.start(); } } class Example { public synchronized void execute() { for (int i = 0; i < 10; ++i) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Hello: " + i); } } } class Thread1 extends Thread { private Example example; public Thread1(Example example) { this.example = example; } @Override public void run() { example.execute(); } }
如果不加synchronized关键字,则两个线程同时执行execute()方法,输出是两组并发的。
如果加上synchronized关键字,则会先输出一组0到9,然后再输出下一组,说明两个线程是顺次执行的。
4.5、wait()、notify()
参考http://www.cnblogs.com/mengdd/archive/2013/02/20/2917956.html
wait()方法使得当前线程必须要等待并释放所有锁,等到另外一个线程调用notify()或者notifyAll()方法。
notify()方法会唤醒一个等待当前对象的锁的线程。如果多个线程在等待,它们中的一个将会选择被唤醒。这种选择是随意的,和具体实现有关。(线程等待一个对象的锁是由于调用了wait方法中的一个)
实例:利用两个线程,对一个整形成员变量进行变化,一个对其增加,一个对其减少,利用线程间的通信,实现该整形变量0101这样交替的变更。
NumberTest public class NumberHolder { private int number; public synchronized void increase() { if (0 != number) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 能执行到这里说明已经被唤醒 // 并且number为0 number++; System.out.println(number); // 通知在等待的线程 notify(); } public synchronized void decrease() { if (0 == number) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 能执行到这里说明已经被唤醒 // 并且number不为0 number--; System.out.println(number); notify(); } } public class IncreaseThread extends Thread { private NumberHolder numberHolder; public IncreaseThread(NumberHolder numberHolder) { this.numberHolder = numberHolder; } @Override public void run() { for (int i = 0; i < 20; ++i) { // 进行一定的延时 try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } // 进行增加操作 numberHolder.increase(); } } } public class DecreaseThread extends Thread { private NumberHolder numberHolder; public DecreaseThread(NumberHolder numberHolder) { this.numberHolder = numberHolder; } @Override public void run() { for (int i = 0; i < 20; ++i) { // 进行一定的延时 try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { e.printStackTrace(); } // 进行减少操作 numberHolder.decrease(); } } } public class NumberTest { public static void main(String[] args) { NumberHolder numberHolder = new NumberHolder(); Thread t1 = new IncreaseThread(numberHolder); Thread t2 = new DecreaseThread(numberHolder); t1.start(); t2.start(); } }