1、线程的基本概念
例子:
分析:
2、线程的创建和启动
第一种线程的创建:
定义一个线程类来实现Runner接口
例子:
package com.zhj.www;
import java.lang.Thread;
public class TestThread1 {public static void main(String[] args) {Runner1 runner1 = new Runner1();Thread myThread = new Thread(runner1);myThread.start();//这行注释掉的话,线程就不会执行。for(int i=0;i<100;i++) {System.out.println("Main Thread:-----" + i);}}
}
class Runner1 implements Runnable{public void run() {for(int i = 0;i<100;i++) {System.out.println("Runner1:" + i);}}
}
运行结果:
我们会发现,主线程,和子线程是交替执行的。
但是呢,要注意:
但是若是直接调用run方法,是方法调用,两者之间天壤之别,只有执行完成一个才会去执行另一个。
package com.zhj.www;
import java.lang.Thread;
public class TestThread1 {public static void main(String[] args) {Runner1 runner1 = new Runner1();//Thread myThread = new Thread(runner1);runner1.run();//myThread.start();//这行注释掉的话,线程就不会执行。for(int i=0;i<100;i++) {System.out.println("Main Thread:-----" + i);}}
}
class Runner1 implements Runnable{public void run() {for(int i = 0;i<100;i++) {System.out.println("Runner1:" + i);}}
}
证明如下:
第二种线程的创建:
定义一个Thread的子类并重写其run方法。
例子:
package com.zhj.www;
import java.lang.Thread;
public class TestThread1 {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();for(int i=0;i<100;i++) {System.out.println("Main Thread:-----" + i);}}
}
class MyThread extends Thread{public void run() {for(int i = 0;i<100;i++) {System.out.println("Runner1:" + i);}}
}
此时,已经新建一个MyThread类继承自Thread类,所以就不用new一个Thread 的对象出来了,而只需要new一个MyThread的子对象。然后调用其start()方法。
执行结果:
我们发现和第一种创建线程的结果是一样的,也是交替执行。但是两个线程分得到的时间片并不一定是相同的。
两个方式有什么区别呢?继承Thread类的方式(第二种方式)比较死,只能从一个类继承,第一种方式呢?比较灵活实现接口,还可以从其他类继承。只要能实现接口,就不要从Thread类继承。
线程状态转换:
1、sleep方法:
package com.zhj.www;import java.util.*;public class TestInterrupt {public static void main(String[] args) {MyThread thread = new MyThread();thread.start();try {Thread.sleep(10000);//主线程睡眠}catch (InterruptedException e) {}//thread.interrupt();//睡着的时候打断,太粗暴了//为什么不用它呢?thread.flag = false;}
}class MyThread extends Thread{boolean flag = true;public void run() {while(flag) {System.out.println("==="+new Date()+"===");try {sleep(1000);} catch (InterruptedException e) {return;}}}
}
运行结果:
2、join方法:
栗子:
package com.zhj.www;public class TestJoin {public static void main(String[] args) {MyThread2 t1 = new MyThread2("abcdef");t1.start();try {t1.join();//合共}catch (InterruptedException e) {}for(int i = 1;i<=10;i++) {System.out.println("I am main thread");}}
}
class MyThread2 extends Thread{public MyThread2(String s) {super(s);}public void run() {for(int i = 0; i<=10;i++) {System.out.println("I am "+ getName()+" (i:)"+i);try {sleep(1000);} catch (InterruptedException e) {return;}}}
}
运行结果:
3、yield方法:
package com.zhj.www;import java.util.*;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();}}}
}
运行结果:
t1到10的倍数切换t2,t2到10的倍数切换t1;
上例子:
package com.zhj.www;public class TestPriority {public static void main(String[] args) {Thread t1 = new Thread(new T1());Thread t2 = new Thread(new T2());t1.setPriority(Thread.NORM_PRIORITY+3);//t1得到的执行时间长t1.start();t2.start();}
}
class T1 implements Runnable{public void run() {for(int i =0;i< 100;i++) {System.out.println("T1: "+ i);}}
}
class T2 implements Runnable{public void run() {for(int i =0;i< 100;i++) {System.out.println("-------T2: "+ i);}}
}
运行一下:
可以发现:t1比t2运行的时间长。
--------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------
额外的栗子:
--------------------------------------------------------------------------------------
TestThread2.java
package com.zhj.www;public class TestThread2 {public static void main(String[] args) {Runner2 r = new Runner2();Thread t1 = new Thread(r);Thread t2 = new Thread(r);t1.start();t2.start();}
}class Runner2 implements Runnable{public void run() {for(int i = 0; i <= 30; i++) {System.out.println("No: "+ i);}}
}
运行一下:
TestThread3.java
package com.zhj.www;public class TestThread3 {public static void main(String[] args) {Runner3 runner3 = new Runner3();Thread thread = new Thread(runner3);thread.start();}
}
class Runner3 implements Runnable {public void run() {for(int i = 0; i<30;i++) {if(i%10 == 0 && i != 0) {try {Thread.sleep(2000);} catch (InterruptedException e) {}}System.out.println("No. " + i);}}
}
当i 是 10的倍数时,会睡眠2s。
运行结果:
TestThread4.java
package com.zhj.www;public class TestThread4 {public static void main(String[] args) {Runner4 r = new Runner4();Thread t = new Thread(r);t.start();for(int i = 0; i< 100000 ; i++) {if(i%10000 == 0 & i>0) {System.out.println("in thread main i =" + i);} }System.out.println("Thread mian is over");r.shutDown();}
}class Runner4 implements Runnable{private boolean flag = true;public void run() {int i = 0;while(flag == true) {System.out.println(" " + i++);}}public void shutDown() {flag = false;}
}
主要:怎么让一个正常执行的线程停止。
run方法结束,线程就结束。
运行结果:
TestThread5.java(关于join方法)
package com.zhj.www;public class TestThread5 {public static void main(String[] args) {Runner5 r = new Runner5();Thread thread = new Thread(r);thread.start();try {thread.join();}catch (InterruptedException e) {}for(int i = 0; i<50;i++) {System.out.println("主线程:"+ i);}}
}
class Runner5 implements Runnable{public void run(){for(int i= 0 ;i<50;i++) {System.out.println("SubThread: " + i);}}
}
运行结果:
TestThread6.java
package com.zhj.www;public class TestThread6 {public static void main(String[] args) {Thread thread = new Runner6();thread.start();for(int i = 0; i<50 ;i++) {System.out.println("MainThread: "+ i);}}
}class Runner6 extends Thread{public void run() {System.out.println(Thread.currentThread().isAlive());for(int i = 0;i<50;i++) {System.out.println("SubThread: " + i);}}
}
----------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------
线程同步
自身是一个线程类。
分析内存:
分析完内存,我们运行一下:
package com.zhj.www;public class TestSync implements Runnable{Timer timer =new Timer();public static void main(String[] args) {TestSync testSync = new TestSync();Thread t1 = new Thread(testSync);Thread t2 = new Thread(testSync);t1.setName("t1");t2.setName("t2");t1.start();t2.start();}public void run() {timer.add(Thread.currentThread().getName());}
}class Timer{private static int num = 0;public void add(String name ) {num++;try {Thread.sleep(1);} catch (InterruptedException e) {}System.out.println(name+",你是第"+num+"个使用timer的线程");}
}
运行一下:
结果为什么是这样呢?感觉哪里不对。
线程在执行这个方法时,被另一个线程打断了。写sleep,是为了
放大这个效果。
怎么解决呢?
在执行的时候,锁定当前对象。一个执行进入到锁住区域时,另一个
线程不可打扰。
如下:
public void add(String name ) {synchronized (this) {num++;try {Thread.sleep(1);} catch (InterruptedException e) {}System.out.println(name+",你是第"+num+"个使用timer的线程");}}
互斥锁。
另外简便的写法:
public synchronized void add(String name ) {//synchronized (this) {num++;try {Thread.sleep(1);} catch (InterruptedException e) {}System.out.println(name+",你是第"+num+"个使用timer的线程");//}}
执行这个方法时,锁住当前对象。
睡着的时候,依然抱着这把锁,其他的人如果要执行这个方法必须等他执行完这个方法。