基础知识《四》---Java多线程学习总结
一、线程的基本概念
简单的说:线程就是一个程序里不同的执行路径,在同一个时间点上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(); //拿到当前线程
六、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
七、join和yield方法
t.join(); //t的run()方法完才会继续执行当前线程方法体
//也就是两个线程变成了一个线程
join方法的功能就是使异步执行的线程变成同步执行。也就是说,当调用线程实例的start方法后,这个方法会立即返回,如果在调用start方法后后需要使用一个由这个线程计算得到的值,就必须使用join方法。如果不使用join方法,就不能保证当执行到start方法后面的某条语句时,这个线程一定会执行完。
下面的代码演示了join的用法。
1 package mythread; 2 3 public class JoinThread extends Thread 4 { 5 public static int n = 0; 6 7 static synchronized void inc() 8 { 9 n++; 10 } 11 public void run() 12 { 13 for (int i = 0; i < 10; i++) 14 try 15 { 16 inc(); 17 sleep(3); // 为了使运行结果更随机,延迟3毫秒 18 19 } 20 catch (Exception e) 21 { 22 } 23 } 24 public static void main(String[] args) throws Exception 25 { 26 27 Thread threads[] = new Thread[100]; 28 for (int i = 0; i < threads.length; i++) // 建立100个线程 29 threads[i] = new JoinThread(); 30 for (int i = 0; i < threads.length; i++) // 运行刚才建立的100个线程 31 threads[i].start(); 32 if (args.length > 0) 33 for (int i = 0; i < threads.length; i++) // 100个线程都执行完后继续 34 threads[i].join(); 35 System.out.println("n=" + JoinThread.n); 36 } 37 }
在例程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(); //暂停当前正在执行的线程对象,并执行其他线程。方法为静态
//哪个线程体执行此方法,哪个线程让步
1 public class TestYield { 2 public static void main(String[] args) { 3 MyThread3 t1 = new MyThread3("t1"); 4 MyThread3 t2 = new MyThread3("t2"); 5 t1.start(); t2.start(); 6 } 7 } 8 class MyThread3 extends Thread { 9 MyThread3(String s){super(s);} 10 public void run(){ 11 for(int i =1;i<=100;i++){ 12 System.out.println(getName()+": "+i); 13 if(i%10==0){ 14 yield(); 15 } 16 } 17 } 18 }
八、线程优先级别
线程的优先级用数字表示,范围从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.线程死锁
1 public class TestDeadLock implements Runnable { 2 public int flag = 1; 3 static Object o1 = new Object(), o2 = new Object(); 4 public void run() { 5 System.out.println("flag=" + flag); 6 if(flag == 1) { 7 synchronized(o1) { 8 try { 9 Thread.sleep(500); 10 } catch (Exception e) { 11 e.printStackTrace(); 12 } 13 synchronized(o2) { 14 System.out.println("1"); 15 } 16 } 17 } 18 if(flag == 0) { 19 synchronized(o2) { 20 try { 21 Thread.sleep(500); 22 } catch (Exception e) { 23 e.printStackTrace(); 24 } 25 synchronized(o1) { 26 System.out.println("0"); 27 } 28 } 29 } 30 } 31 32 public static void main(String[] args) { 33 TestDeadLock td1 = new TestDeadLock(); 34 TestDeadLock td2 = new TestDeadLock(); 35 td1.flag = 1; 36 td2.flag = 0; 37 Thread t1 = new Thread(td1); 38 Thread t2 = new Thread(td2); 39 t1.start(); 40 t2.start(); 41 42 } 43 }
十、生产者消费者问题
1 public class ProducerConsumer { 2 public static void main(String[] args) { 3 SyncStack ss = new SyncStack(); 4 Producer p = new Producer(ss); 5 Consumer c = new Consumer(ss); 6 new Thread(p).start(); 7 new Thread(p).start(); 8 new Thread(p).start(); 9 new Thread(c).start(); 10 } 11 } 12 13 class WoTou { 14 int id; 15 WoTou(int id) { 16 this.id = id; 17 } 18 public String toString() { 19 return "WoTou : " + id; 20 } 21 } 22 23 class SyncStack { //栈实现 24 int index = 0; 25 WoTou[] arrWT = new WoTou[6]; //相当于装物品的篮子 26 27 public synchronized void push(WoTou wt) { //生产物品,线程安全 28 while(index == arrWT.length) { //当篮子满了线程等待 29 try { 30 this.wait(); 31 } catch (InterruptedException e) { 32 e.printStackTrace(); 33 } 34 35 } 36 this.notifyAll(); //开始生产时,叫醒等待的其他线程开始消费 37 arrWT[index] = wt; 38 index ++; 39 } 40 41 public synchronized WoTou pop() { //消费物品,线程安全 42 while(index == 0) { //如果篮子空了 43 try { 44 this.wait(); //线程等待,等待生产者开始 45 //生产,叫醒此线程 46 } catch (InterruptedException e) { 47 e.printStackTrace(); 48 } 49 50 } 51 this.notifyAll(); //消费时喊醒生产者生产 52 index--; 53 return arrWT[index]; 54 } 55 } 56 57 class Producer implements Runnable { //生产者类 58 SyncStack ss = null; 59 Producer(SyncStack ss) { 60 this.ss = ss; 61 } 62 63 public void run() { 64 for(int i=0; i<20; i++) { //生产20个 65 WoTou wt = new WoTou(i); 66 ss.push(wt); 67 System.out.println("生产了:" + wt); 68 try { 69 Thread.sleep((int)(Math.random() * 200)); 70 } catch (InterruptedException e) { 71 e.printStackTrace(); 72 } 73 } 74 } 75 } 76 77 class Consumer implements Runnable { 78 SyncStack ss = null; 79 Consumer(SyncStack ss) { 80 this.ss = ss; 81 } 82 83 public void run() { 84 for(int i=0; i<20; i++) { //消费20个 85 WoTou wt = ss.pop(); 86 System.out.println("消费了: " + wt); 87 try { 88 Thread.sleep((int)(Math.random() * 1000)); 89 } catch (InterruptedException e) { 90 e.printStackTrace(); 91 } 92 } 93 } 94 }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。