线程是一个程序里面不同的执行路径(理解这个就可以了)
1.线程的基本概念
可以通过创建Thread的实例来创建新的线程。
每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。
通过调用Thread类的start()方法来启动一个线程。
2.线程的创建和启动
第一种
定义线程类实现Runnable接口
Thread myThread = new Thread(target) //target为Runnable接口类型。
Runnable中只有一个方法:
public void run();//用以定义线程运行体。
使用Runnable接口可以为多个线程提供共享的数据。
在实现Runnable接口的类的run方法定义中可以使用Thread的静态方法:
public static Thread currentThread() //获取当前线程的引用。
第二种
可以定义一个Thread的子类并重写其run方法:
class MyThread extends Thread{
public void run(){...}
}
然后生成该类的对象:
MyThread myThread = new MyThread(...)
例子1:使用Runnable接口实现
1 //main主线程和子线程并行执行 2 public class TestThread1 { 3 public static void main(String[] args) { 4 Runnable1 r = new Runnable1(); 5 //r.run();//方法调用 6 Thread thread = new Thread(r); 7 thread.start();//启动一个新线程 8 for(int i=0;i<100;i++){ 9 System.err.println("MainThread-----"+i); 10 } 11 } 12 } 13 14 class Runnable1 implements Runnable { 15 public void run() { 16 for(int i=0;i<100;i++){ 17 System.out.println("Runner1:"+i); 18 } 19 } 20 }
例子2:从Thread类继承
1 //main主线程和子线程并行执行 2 public class TestThread1 { 3 public static void main(String[] args) { 4 Runnable1 thread = new Runnable1(); 5 thread.start();//启动一个新线程 6 for(int i=0;i<100;i++){ 7 System.err.println("MainThread-----"+i); 8 } 9 } 10 } 11 12 class Runnable1 extends Thread{ 13 public void run() { 14 for(int i=0;i<100;i++){ 15 System.out.println("Runner1:"+i); 16 } 17 } 18 }
3.常用方法
sleep方法
可以调用Thread的静态方法:
public static void sleep(long milis) throws InterruptedExecption使得当前线程休眠(暂时停止执行millis毫秒)。
由于是静态方法,sleep可以由类名之间调用:
Thread.sleep(...)
例子3
1 public class TestInterrupt { 2 public static void main(String[] args) { 3 MyThread thread = new MyThread(); 4 thread.start(); 5 try { 6 Thread.sleep(10000);//在哪个线程里调用Thread.sleep方法就让哪个线程睡眠 7 } catch (InterruptedException e) {} 8 thread.interrupt();//子线程结束(不是让子线程结束的最好的方法,比较粗暴,可能会导致打开的资源来不及关) 9 //thread.stop();//(已废弃)方式比interrupt更粗暴。 10 } 11 } 12 13 class MyThread extends Thread{ 14 @Override 15 public void run() {//不可以在后面写throws exception,原因是run重写的,重写的方法不能抛出比被重写方法不同的异常 16 while(true){ 17 System.err.println("===="+new Date()+"===="); 18 try { 19 sleep(1000); 20 } catch (InterruptedException e) { 21 return; 22 } 23 } 24 } 25 }
例子4:使用一个变量控制子程序结束
1 public class TestInterrupt { 2 public static void main(String[] args) { 3 MyThread thread = new MyThread(); 4 thread.start(); 5 try { 6 Thread.sleep(10000); 7 } catch (InterruptedException e) {} 8 thread.flag = false; 9 } 10 } 11 12 class MyThread extends Thread{ 13 boolean flag = true;//定义一个变量来控制 14 public void run() { 15 while(flag){ 16 System.err.println("===="+new Date()+"===="); 17 try { 18 sleep(1000); 19 } catch (InterruptedException e) { 20 return; 21 } 22 } 23 } 24 }
join方法
合并某个线程
例子5
1 public class TestJoin { 2 public static void main(String[] args) { 3 MyThread2 t1 = new MyThread2("t1"); 4 t1.start(); 5 try { 6 t1.join();//合并t1,把t1合并到主线程来,等t1执行完才执行主线程的 7 } catch (Exception e) {} 8 for(int i=0;i<10;i++){ 9 System.err.println("main Thread is "+i); 10 } 11 } 12 } 13 14 class MyThread2 extends Thread{ 15 public MyThread2(String s) { 16 super(s); 17 } 18 @Override 19 public void run() { 20 for(int i=0;i<10;i++){ 21 System.err.println("i am "+getName()); 22 try { 23 sleep(1000); 24 } catch (Exception e) { 25 return; 26 } 27 } 28 } 29 }
yield方法(用的不多)
让出CPU,给其他线程执行的机会
例子6
1 public class TestYeild { 2 public static void main(String[] args) { 3 MyThread3 thread3 = new MyThread3("t3"); 4 MyThread3 thread1 = new MyThread3("t1"); 5 thread3.start(); 6 thread1.start(); 7 } 8 } 9 10 class MyThread3 extends Thread{ 11 public MyThread3(String s) { 12 super(s); 13 } 14 @Override 15 public void run() { 16 for(int i=0;i<50;i++){ 17 System.err.println(getName()+"-----"+ i); 18 if (i%10==0) { 19 yield(); 20 } 21 } 22 } 23 }
线程的优先级别
用数字表示,范围从1到10,默认是5,优先级越高的得到的CPU的执行的时间片就会越多。
例子6
1 public class TestPriority { 2 public static void main(String[] args) { 3 Thread thread1 = new Thread(new t1()); 4 Thread thread2 = new Thread(new t2()); 5 thread1.setPriority(Thread.NORM_PRIORITY+3); 6 thread1.start(); 7 thread2.start(); 8 } 9 } 10 11 class t1 implements Runnable { 12 public void run() { 13 for(int i=0;i<10;i++){ 14 System.err.println("t1:"+i); 15 } 16 } 17 } 18 19 class t2 implements Runnable { 20 public void run() { 21 for(int i=0;i<10;i++){ 22 System.err.println("--------t2:"+i); 23 } 24 } 25 }
执行结果
t1:0 t1:1 --------t2:0 t1:2 t1:3 t1:4 t1:5 t1:6 t1:7 t1:8 t1:9 --------t2:1 --------t2:2 --------t2:3 --------t2:4 --------t2:5 --------t2:6 --------t2:7 --------t2:8 --------t2:9
4.线程同步
例子7:不使用线程同步会出现以下问题(结果不对)
1 public class TestSync implements Runnable { 2 Timer timer = new Timer(); 3 public static void main(String[] args) { 4 TestSync test = new TestSync(); 5 Thread t1 = new Thread(test); 6 Thread t2 = new Thread(test); 7 t1.setName("t1"); 8 t2.setName("t2"); 9 t1.start(); 10 t2.start(); 11 } 12 public void run() { 13 timer.add(Thread.currentThread().getName()); 14 } 15 } 16 17 class Timer{ 18 private static int num =0; 19 public void add(String name) { 20 num++; 21 try { 22 Thread.sleep(1); 23 } catch (InterruptedException e) {} 24 System.err.println(name +"你是第"+num+"个使用timer的线程"); 25 26 } 27 }
结果
t2你是第2个使用timer的线程
t1你是第2个使用timer的线程
例子8:
1 public class TestSync implements Runnable { 2 Timer timer = new Timer(); 3 public static void main(String[] args) { 4 TestSync test = new TestSync(); 5 Thread t1 = new Thread(test); 6 Thread t2 = new Thread(test); 7 t1.setName("t1"); 8 t2.setName("t2"); 9 t1.start(); 10 t2.start(); 11 } 12 public void run() { 13 timer.add(Thread.currentThread().getName()); 14 } 15 } 16 17 class Timer{ 18 private static int num =0; 19 public void add(String name) { 20 // public synchronized void add(String name) { //也可以写成这样 21 synchronized (this) {//该方法被执行过程中当前对象被锁定 22 num++; 23 try { 24 Thread.sleep(1); 25 } catch (InterruptedException e) {} 26 System.err.println(name +"你是第"+num+"个使用timer的线程"); 27 } 28 } 29 }
结果
t1你是第1个使用timer的线程
t2你是第2个使用timer的线程
5.多线程会造成的问题
死锁
例子9
1 public class TestDeadLocak implements Runnable{ 2 public int flag=1; 3 static Object o1=new Object(),o2=new Object(); 4 5 @Override 6 public void run() { 7 System.err.println("flag="+flag); 8 if (flag==1) { 9 synchronized (o1) { 10 try { 11 Thread.sleep(500); 12 } catch (Exception e) { 13 e.printStackTrace(); 14 } 15 synchronized (o2) { 16 System.err.println("1"); 17 } 18 } 19 20 } 21 22 if (flag==0) { 23 synchronized(o2){ 24 try { 25 Thread.sleep(500); 26 } catch (Exception e) { 27 e.printStackTrace(); 28 } 29 synchronized (o1) { 30 System.err.println("0"); 31 } 32 } 33 } 34 } 35 36 public static void main(String[] args) { 37 TestDeadLocak t = new TestDeadLocak(); 38 TestDeadLocak t0 = new TestDeadLocak(); 39 t0.flag=0; 40 Thread t1 = new Thread(t); 41 Thread t2 = new Thread(t0); 42 t1.start(); 43 t2.start(); 44 } 45 }
6.生产者消费者问题
例子10
1 /* 2 * 生产者消费者问题 3 * 要 点: 4 * 1. 共享数据的不一致性/临界资源的保护 5 * 2. Java对象锁的概念 6 * 3. synchronized关键字/wait()及notify()方法 7 */ 8 public class ProducerConsumer { 9 public static void main(String[] args) { 10 SyncStack stack = new SyncStack(); 11 Runnable p = new Producer(stack); 12 Runnable c = new Customer(stack); 13 Thread p1 =new Thread(p); 14 Thread c1 = new Thread(c); 15 p1.start(); 16 c1.start(); 17 } 18 } 19 20 class SyncStack{ //支持多线程同步操作的堆栈的实现 21 private int index =0; 22 private char[] data = new char[6]; 23 public synchronized void push(char c) { 24 if(index == data.length){ 25 try { 26 this.wait(); 27 } catch (InterruptedException e) { 28 } 29 } 30 this.notify(); 31 data[index] = c; 32 index++; 33 } 34 public synchronized char pop() { 35 if(index == 0){ 36 try { 37 this.wait(); 38 } catch (InterruptedException e) { 39 } 40 } 41 this.notify(); 42 index--; 43 return data[index]; 44 } 45 } 46 47 class Producer implements Runnable{ 48 SyncStack stack; 49 public Producer(SyncStack s) { 50 stack =s; 51 } 52 53 @Override 54 public void run() { 55 for(int i=0;i<20;i++){ 56 char c =(char)(Math.random()*26+'A'); 57 stack.push(c); 58 System.err.println("producer"+c); 59 try { 60 Thread.sleep((int)Math.random()*1000); 61 } catch (InterruptedException e) {} 62 } 63 64 } 65 66 } 67 68 class Customer implements Runnable{ 69 SyncStack stack; 70 public Customer(SyncStack s) { 71 stack =s; 72 } 73 74 @Override 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 }