java线程详解二
线程的优先级
线程调度:按照特定的机制为线程分配CPU的时间片段的行为,java程序再运行的时候,由java虚拟机负责线程的调度
线程调度的实现方式:1、分时调度,2、抢占式调度
分时调度:指让所有线程轮流获取CPU的使用权,并为每个线程平均分配CPU的时间片段
抢占式调度:指选择优先级较高的线程执行,如果所有的线程优先级相同,则会随机选择一个线程执行,java虚拟机正是采用这个调度模式。
线程优先级范例一:
1 public class ThreadTest5 { 2 3 public static void main(String[] args) { 4 5 Thread th = new Thread(new Runnable() { 6 @Override 7 public void run() { 8 9 for (int i = 0; i <100 ; i++) { 10 11 System.out.println(Thread.currentThread().getName()); 12 } 13 14 15 } 16 }); 17 th.setPriority(1);//设置该线程的优先级 18 th.start();//开启这个线程,并执行run方法 19 System.out.println(th.getPriority());//获取该线程的优先级 20 21 22 Thread th2 = new Thread(new Runnable() { 23 @Override 24 public void run() { 25 26 for (int i = 0; i <100 ; i++) { 27 28 System.out.println(Thread.currentThread().getName()); 29 } 30 31 32 } 33 }); 34 th2.setPriority(10);//设置该线程的优先级 35 th2.start();//开启这个线程,并执行run方法 36 System.out.println(th2.getPriority());//获取该线程的优先级 37 38 39 40 41 } 42 }
注意:自定义的线程和main方法主线程的优先级默认都是5,线程的优先级用数据表示,范围1~10
线程同步
什么是线程安全:多线程应用程序同时访问共享对象时,由于线程之间相互抢占CPU的控制权,会造成一个线程夹在另一个线程的执行过程中运行,会造成错误的执行的过程
synchronized关键字:确保共享对象只能被一个线程访问,这种机制称为线程同步或者线程互斥,java中的线程同步是基于对象锁的概念。
synchronized关键字使用范例
1 public class ThreadTest6 { 2 3 public static void main(String[] args) { 4 5 maipiao maipiao = new maipiao(); 6 7 Thread t1 = new Thread(maipiao,"学生"); 8 Thread t2 = new Thread(maipiao,"白领"); 9 Thread t3 = new Thread(maipiao,"工人"); 10 11 t1.start(); 12 t2.start(); 13 t3.start(); 14 15 } 16 17 18 19 20 } 21 22 /** 23 *定义一个线程类 24 */ 25 class maipiao implements Runnable{ 26 27 private Integer ticket = 100;//定义100张票 28 private Boolean state = true; 29 @Override 30 public void run() { 31 32 while (state){ 33 function(); 34 } 35 36 } 37 38 /** 39 * 买票的实现方法 40 *synchronized关键字:加在方法上该方法就是一个同步方法,在某一个时间片段只能由一个线程方法该方法 41 */ 42 43 public /*synchronized*/ void function(){ 44 45 //也可以用同步代码块的方式保持同步 46 synchronized (this){ 47 if(ticket<=0){ 48 state=false; 49 return; 50 } 51 52 try { 53 Thread.sleep(1000);//让线程睡眠1秒 54 } catch (InterruptedException e) { 55 e.printStackTrace(); 56 } 57 58 if(state){ 59 System.out.println(Thread.currentThread().getName()+"-抢到了第"+ticket--+"张票"); 60 } 61 } 62 63 64 } 65 }
同步方法和同步代码块的作用是一样的,只是控制的范围不一样,范围越大,性能越差,所以一般使用同步代码块来保持线程同步
线程之间的通信
列举3个重要的方法:均是java.lang.Object中的方法,只能在同步方法或者同步代码块中使用,否则会抛出异常
wait()方法:中断方法的执行,使当前线程等待,暂时让出CPU的使用权,并允许其他线程使用该同步方法。
notify()方法:唤醒单个使用同步方法等待的线程
notifyall()方法:唤醒所有使用同步方法等待的线程
生产者消费者问题
1 /* 范例名称:生产者--消费者问题 2 * 源文件名称:ProducerConsumer.java 3 * 要 点: 4 * 1. 共享数据的不一致性/临界资源的保护 5 * 2. Java对象锁的概念 6 * 3. synchronized关键字/wait()及notify()方法 7 */ 8 9 public class ProducerConsumer { 10 public static void main(String args[]){ 11 SyncStack stack = new SyncStack(); 12 Runnable p=new Producer(stack); 13 Runnable c = new Consumer(stack); 14 Thread p1 = new Thread(p); 15 Thread c1 = new Thread(c); 16 17 p1.start(); 18 c1.start(); 19 } 20 } 21 22 23 class SyncStack{ //支持多线程同步操作的堆栈的实现 24 private int index = 0; 25 private char[] data = new char[6]; 26 27 public synchronized void push(char c){ 28 if(index == data.length){ 29 try{ 30 this.wait(); 31 }catch(InterruptedException e){} 32 } 33 this.notify(); 34 data[index] = c; 35 index++; 36 } 37 38 public synchronized char pop(){ 39 if(index ==0){ 40 try{ 41 this.wait(); 42 }catch(InterruptedException e){} 43 } 44 this.notify(); 45 index--; 46 return data[index]; 47 } 48 } 49 50 51 class Producer implements Runnable{ 52 SyncStack stack; 53 public Producer(SyncStack s){ 54 stack = s; 55 } 56 public void run(){ 57 for(int i=0; i<20; i++){ 58 char c =(char)(Math.random()*26+'A'); 59 stack.push(c); 60 System.out.println("produced:"+c); 61 try{ 62 Thread.sleep((int)(Math.random()*1000)); 63 }catch(InterruptedException e){ 64 } 65 } 66 } 67 } 68 69 70 class Consumer implements Runnable{ 71 SyncStack stack; 72 public Consumer(SyncStack s){ 73 stack = s; 74 } 75 public void run(){ 76 for(int i=0;i<20;i++){ 77 char c = stack.pop(); 78 System.out.println("消费:"+c); 79 try{ 80 Thread.sleep((int)(Math.random()*1000)); 81 }catch(InterruptedException e){ 82 } 83 } 84 } 85 }