1、操作系统能同时运行多个应用程序,每个应用程序就是一个进程
一个进程可以同时运行多个线程,每个线程负责处理一个任务
2、线程的功能:一个应用程序可以同时去完成多个功能
3、应用程序启动后,会自动创建一个主线程(Android中叫UI线程),其他的线程都称之子线程
4、线程创建线程:
A、创建一个类继承自Thread或者实现Runnable接口,他们都需要重写run()方法,该方法是线程的主体,功能代码必须放在run()方法
B、调用Thread的start()方法启动线程,该方法会自动调用run()方法,run()方法中的代码执行结束后,线程会自动销毁
C、线程对象不能重复启动,比较下面的写法
Thread t = new Thread();
t.start();
t.start();
上面写法错误,因为线程完成后会销毁,所以不能重复调用start()
----------------
线程启动之前一定要先创建
new Thread().start();
new Thread().start();
5、创建线程的方法
A、继承Thread类,该方法用得比较少
public class MyThread extends Thread{
public void run(){
Thread.sleep(1000);//休眠
}
}
MyThread t = new MyThread();
t.start();
B、实现Runnable接口,99%的时候都用此方法
public class MyThread implements Runnable{
public void run(){
Thread.sleep(1000);
}
}
Thread t = new Thread(new MyThread());
t.start();
案例1:在应用程序中,两个任务同时运行,一个是显示时钟,另一个显示偶数。
public class EvenTask implements Runnable{
@Override
public void run() {
for(int i = 0; i < 100; i ++){
if(i % 2 == 0){
System.out.println(i);
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class TimeTask implements Runnable{
private Date now = new Date();
@Override
public void run() {
while(true){
//打印现在的时间
System.out.println(now.toLocaleString());
//更新时间
now.setTime(System.currentTimeMillis());
//输入一次时间后线程休眠1秒钟
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class Client {
public static void main(String[] args) {
Thread time = new Thread(new TimeTask());
time.start();
Thread even = new Thread(new EvenTask());
even.start();
/*new Thread(new Runnable() {
@Override
public void run() {
}
}).start();*/
}
}
案例2: 利用多线程求解某范围素数,每个线程负责1000范围:线程1找1-1000;线程2找1001-2000;线程3找2001-3000。编程程序将每个线程找到的素数及时打印。
/**
* 判断素数
* @author Administrator
*
*/
public class Prime {
/**
* 判断n是否为素数,如果是,返回true,否则返回false
* @param n
* @return
*/
public static boolean isPrime(int n){
for(int i = 2; i < n; i ++){
if(n % i == 0){
return false;
}
}
return true;
}
}
public class Thread1 implements Runnable{
@Override
public void run() {
for(int i = 1; i <= 1000; i ++){
if(Prime.isPrime(i)){
System.out.println(i);
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class Thread2 implements Runnable{
@Override
public void run() {
for(int i = 1001; i <= 2000; i ++){
if(Prime.isPrime(i)){
System.out.println(i);
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class Thread3 implements Runnable{
@Override
public void run() {
for(int i = 2001; i <= 3000; i ++){
if(Prime.isPrime(i)){
System.out.println(i);
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class Test {
public static void main(String[] args) {
Thread t1 = new Thread(new Thread1());
Thread t2 = new Thread(new Thread2());
Thread t3 = new Thread(new Thread3());
try {
t1.start();
//t1.join();
t2.start();
//t2.join();
t3.start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
6、线程的状态及转换
A、线程对象创建后,线程处于就绪状态
B、调用start()方法后,线程处于可运行状态,不一定立即运行,因为此时CPU正在处理其他的任务
C、CPU处理处于可运行状态的线程,线程马上会调用run()方法并处于运行状态
D、线程在运行过程中,如果调用了sleep()或join()方法,线程会处于阻塞状态(阻塞状态是指线程还在内存中,但不会执行任务)
E、线程在运行过程中,调用了yield()方法,该线程会主动出让CPU,此时,线程会处理可运行状态
F、线程在运行过程中,如果调用了wait()方法,则线程会处理等待状态,必须要通过notify()或notifyAll()才能唤醒线程
7、Thread中的方法
start():启动线程
run():线程主体,完成任务
sleep():休眠
join():让线程处于阻塞状态,CPU处理完前面的线程后再处理后面的线程
yield():主动让出CPU的控制权
wait():线程处于等待状态,此时,线程成了植物人
notify()、notifyAll():专门用于唤醒处于等待状态的线程
8、线程状态转换关系
9、线程同步用于保证一个共享资源在同一时刻只能有一个线程访问,如果其他线程也要访问,就必须等待。
10、线程同步时,使用不同的方法需要明白的共享资源
A、同步方法
synchronized public void method(){}
共享对象是this
即:同步方法定义在哪个类中,该类的对象就是共享对象
class A{
synchronized public void method(){
}
}
A a = new A(); -> 此时,对象a就是共享对象
案例:
/**
* 共享资源
*
* @author Administrator
*
*/
public class ShareResource {
private int n;
public synchronized void addSelf() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + n++);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
线程1:
public class Task1 implements Runnable {
private ShareResource sr;
public Task1(ShareResource sr) {
super();
this.sr = sr;
}
@Override
public void run() {
sr.addSelf();//同步方法
}
}
线程2:
public class Task2 implements Runnable {
private ShareResource sr;
public Task2(ShareResource sr) {
super();
this.sr = sr;
}
@Override
public void run() {
sr.addSelf();
}
}
测试:
public class Test {
public static void main(String[] args) {
ShareResource sr = new ShareResource();
new Thread(new Task1(sr)).start();
new Thread(new Task2(sr)).start();
}
}
B、同步块
synchronized(object){}
共享对象是object
同步块通常定义在线程中
案例:
共享资源:
public class ShareResource2 {
private int n;
public void addSelf() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + n++);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
线程1:
public class Task3 implements Runnable {
private ShareResource2 sr;//共享对象
public Task3(ShareResource2 sr) {
super();
this.sr = sr;
}
@Override
public void run() {
synchronized(sr){
sr.addSelf();//同步方法
}
}
}
线程2:
public class Task4 implements Runnable {
private ShareResource2 sr;
public Task4(ShareResource2 sr) {
super();
this.sr = sr;
}
@Override
public void run() {
synchronized(sr){
sr.addSelf();//同步方法
}
}
}
测试:
public class Test2 {
public static void main(String[] args) {
ShareResource2 sr = new ShareResource2();
new Thread(new Task3(sr)).start();
new Thread(new Task4(sr)).start();
}
}