本文转载自51cto
一、线程的基本概念
简单的说:线程就是一个程序里不同的执行路径,在同一个时间点上cpu只会有一个线程在执行,Java里的多线程是通过java.lang.Thread类来实现的,每个线程都拥有自己独立的方法栈空间。
二、java线程的创建和启动
第一种
定义线程类实现Runnable接口:
Thread myThread = new Thread(target) //target为Runnable接口类型
Runnable中只有一个方法:
public void run();用以定义线程运行体
第二种
可以定义一个Thread的子类并重写其run方法:
clas MyThread extends Thread{
public void run(){}
}
线程类必须通过执行Thread的start()方法启动一个新的线程,如果调用run()方法是属于方法的调用,不会启动一个新的线程,推荐使用第一种方式创建线程,使用接口较为灵活。
三、线程状态装换
调用线程start()方法时,线程进入就绪状态,Cpu分配时间片,线程进入运行状态,时间片结束,run()方法未执行完,线程进入阻塞状态。
四、线程控制基本方法
isAlive() //判断线程是否还“活着”,即线程是否还未终止
getPriority() //获得线程的优先级数值
setPriority() //设置线程的优先级指数
Thread.sleep() //静态方法,将当前线程睡眠指定毫秒数
join() //调用某线程的该方法,将当前线程与该线程合并,
//即等待该线程结束,再回复当前线程的运行。
yield() //让出CPU,当前线程进入就绪状态等待调度
interrupt() //中断线程
wait() //当前线程进入对象的wait pool
notify()/notifyAll //唤醒对象的wait pool中的一个/所有等待线程
五、sleep方法
Thread的静态方法
public static void sleep(long millis)throws InterruptedException
必须对异常进行捕捉
Thread.currentThread(); //拿到当前线程
六、join和yield方法
t.join(); //t的run()方法完才会继续执行当前线程方法体
//也就是两个线程变成了一个线程
join方法的功能就是使异步执行的线程变成同步执行。也就是说,当调用线程实例的start方法后,这个方法会立即返回,如果在调用start方法后后需要使用一个由这个线程计算得到的值,就必须使用join方法。如果不使用join方法,就不能保证当执行到start方法后面的某条语句时,这个线程一定会执行完。
下面的代码演示了join的用法。
package mythread; public class JoinThread extends Thread
{
public static int n = 0; static synchronized void inc()
{
n++;
}
public void run()
{
for (int i = 0; i < 10; i++)
try
{
inc();
sleep(3); // 为了使运行结果更随机,延迟3毫秒 }
catch (Exception e)
{
}
}
public static void main(String[] args) throws Exception
{ Thread threads[] = new Thread[100];
for (int i = 0; i < threads.length; i++) // 建立100个线程
threads[i] = new JoinThread();
for (int i = 0; i < threads.length; i++) // 运行刚才建立的100个线程
threads[i].start();
if (args.length > 0)
for (int i = 0; i < threads.length; i++) // 100个线程都执行完后继续
threads[i].join();
System.out.println("n=" + JoinThread.n);
}
}
在例程2-8中建立了100个线程,每个线程使静态变量n增加10。如果在这100个线程都执行完后输出n,这个n值应该是1000。
1. 测试1
使用如下的命令运行上面程序:
- java mythread.JoinThread
程序的运行结果如下:
n=442
这个运行结果可能在不同的运行环境下有一些差异,但一般n不会等于1000。从上面的结果可以肯定,这100个线程并未都执行完就将n输出了。
2. 测试2
使用如下的命令运行上面的代码:
在上面的命令行中有一个参数join,其实在命令行中可以使用任何参数,只要有一个参数就可以,这里使用join,只是为了表明要使用join方法使这100个线程同步执行。
程序的运行结果如下:
n=1000
无论在什么样的运行环境下运行上面的命令,都会得到相同的结果:n=1000。这充分说明了这100个线程肯定是都执行完了,因此,n一定会等于1000。
t.yield(); //暂停当前正在执行的线程对象,并执行其他线程。方法为静态
//哪个线程体执行此方法,哪个线程让步
public class TestYield {
public static void main(String[] args) {
MyThread3 t1 = new MyThread3("t1");
MyThread3 t2 = new MyThread3("t2");
t1.start(); t2.start();
}
}
class MyThread3 extends Thread {
MyThread3(String s){super(s);}
public void run(){
for(int i =1;i<=100;i++){
System.out.println(getName()+": "+i);
if(i%10==0){
yield();
}
}
}
}
七、interrupt方法一种让线程退出的方式。
1 import java.util.*;
2 public class TestInterrupt{
3 public static void main(String[] args){
4 MyThread t = new MyThread();
5 t.start();
6 try{Thread.sleep(10000);}
7 catch(InterruptedException i){}
8 t.interrupt();
9 }
10 }
11
12 class MyThread extends Thread{
13 public void run(){
14 while(true){
15 try{
16 System.out.println("------"+new Date()+"-----");
17 Thread.sleep(1000);
18 }catch(InterruptedException i){
19 return;
20 }
21 }
22 }
23 }
24
八、线程优先级别
线程的优先级用数字表示,范围从1到10,一个线程的缺省优先级为5.
Thread.MAX_PRIORITY=1
Thread.MIN_PRIORITY=10
Thread.NORM_PRIORITY=5
例:t.setPriority(Thread.NORM_PRIORITY+3);
九、线程同步
1.同步代码块
synchronized(this){ //在执行代码块过程中,不会被其他线程打断
...
}
public sunchronized void method //执行此方法时,当前对象被锁定
在Java语言中,引入了对象互斥锁的概念,保证共享数据操作的完整性,每个对象 都对应一个可称为"互斥锁"的标记,这个标记保证在任一时刻,只能有一个线程访 问该对象。
2.线程死锁
public class TestDeadLock implements Runnable {
public int flag = 1;
static Object o1 = new Object(), o2 = new Object();
public void run() {
System.out.println("flag=" + flag);
if(flag == 1) {
synchronized(o1) {
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
synchronized(o2) {
System.out.println("1");
}
}
}
if(flag == 0) {
synchronized(o2) {
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
synchronized(o1) {
System.out.println("0");
}
}
}
} public static void main(String[] args) {
TestDeadLock td1 = new TestDeadLock();
TestDeadLock td2 = new TestDeadLock();
td1.flag = 1;
td2.flag = 0;
Thread t1 = new Thread(td1);
Thread t2 = new Thread(td2);
t1.start();
t2.start(); }
}
十、生产者消费者问题
public class ProducerConsumer {
public static void main(String[] args) {
SyncStack ss = new SyncStack();
Producer p = new Producer(ss);
Consumer c = new Consumer(ss);
new Thread(p).start();
new Thread(p).start();
new Thread(p).start();
new Thread(c).start();
}
} class WoTou {
int id;
WoTou(int id) {
this.id = id;
}
public String toString() {
return "WoTou : " + id;
}
} class SyncStack { //栈实现
int index = 0;
WoTou[] arrWT = new WoTou[6]; //相当于装物品的篮子 public synchronized void push(WoTou wt) { //生产物品,线程安全
while(index == arrWT.length) { //当篮子满了线程等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
} }
this.notifyAll(); //开始生产时,叫醒等待的其他线程开始消费
arrWT[index] = wt;
index ++;
} public synchronized WoTou pop() { //消费物品,线程安全
while(index == 0) { //如果篮子空了
try {
this.wait(); //线程等待,等待生产者开始
//生产,叫醒此线程
} catch (InterruptedException e) {
e.printStackTrace();
} }
this.notifyAll(); //消费时喊醒生产者生产
index--;
return arrWT[index];
}
} class Producer implements Runnable { //生产者类
SyncStack ss = null;
Producer(SyncStack ss) {
this.ss = ss;
} public void run() {
for(int i=0; i<20; i++) { //生产20个
WoTou wt = new WoTou(i);
ss.push(wt);
System.out.println("生产了:" + wt);
try {
Thread.sleep((int)(Math.random() * 200));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} class Consumer implements Runnable {
SyncStack ss = null;
Consumer(SyncStack ss) {
this.ss = ss;
} public void run() {
for(int i=0; i<20; i++) { //消费20个
WoTou wt = ss.pop();
System.out.println("消费了: " + wt);
try {
Thread.sleep((int)(Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}