Java 第十四课:Java多线程

一、多线程的概念
一个完整的系统支持多种多样的功能,并且可以同时做两件以上的事情。比如你可以边听歌边写文档还可以通过社交软件与朋友沟通,这种多操作的思想我们称为并发,而要完成并发就需要多线程。

多线程和多进程的区别:
	进程是重量级的任务,需要分配它们自己独立的地址空间。
	进程间通信是昂贵和受限的。
	进程间的转换也是很需要花费的。
	
	线程是轻量级的。
	它们共享相同的地址空间并且共同分享同一个进程。
	线程间通信是便宜的,线程间的转换也是低成本的。

二、线程实现方式:
Java的JDK开发包中自带多线程的支持,主要有两种实习那方式:
1. 继承Thread类
2. 实现Runnable接口。

继承Thread类
继承Thread类的方法最大的局限就是不支持多继承。Thread类有两种构造方法:

	1. public Thread(String threadName);
	2. public Thread();
  1. 继承Thread类的实现线程语法格式:
	public class NewThreadName extends Thread {
		@Override
		public void run() {
			//线程执行代码		
		}
	}
	说明:
		当一个类继承Thread类后,就可以在新类中覆盖run()方法,然后调用Thread.start()方法就可以执行线程,调用run()方法。
  1. 启动一个线程:
    new NewThreadName().start();
    注意:如果start()方法调用一个已经启动的线程,系统会抛出IllegalThreadStateException异常。线程启动后,子任务和主线程执行先后顺序是不可预知的。
package lesson3;
import java.util.*;

//MyThreadTest.java
public class MyThreadTest extends Thread {
	
	@Override
	public void run() {
		try {
			for(int i = 0; i < 10; i++) {
				Date date = new Date();
				System.out.println(date);
				Thread.sleep(1000 * 2);
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
	}
}

	public static void javaThreadTest() {
		MyThreadTest myThread = new MyThreadTest();
		myThread.setName("myThreadTest");
		myThread.start();
	}
输出结果:
	Thu Mar 14 18:33:00 CST 2019
	Thu Mar 14 18:33:02 CST 2019
	Thu Mar 14 18:33:04 CST 2019
	Thu Mar 14 18:33:06 CST 2019
	Thu Mar 14 18:33:08 CST 2019
	Thu Mar 14 18:33:10 CST 2019
	Thu Mar 14 18:33:12 CST 2019
	Thu Mar 14 18:33:14 CST 2019
	Thu Mar 14 18:33:16 CST 2019
	Thu Mar 14 18:33:18 CST 2019

实现Runnable接口
如果要创建的线程类已经有一个父类,这时就不能再继承 Thread 类,因为 Java 不支持多继承,所以需要实现 Runnable 接口来实现。

  1. 语法格式:
    public class thread extends Object implements Runnable

  2. Thread 类与 Runnable 有关的构造方法:
    public Thread(Runnable r);
    public Thread(Runnable r, String name);

  3. 步骤:
    创建并实例化Runnable类
    使用带Runnable对象的构造方法创建Thread实例。
    调用start()方法启动线程。

	实例:
	public static void javaThreadTest() {
		MyThreadTest myThread = new MyThreadTest();
		myThread.setName("myThreadTest");
		myThread.start();
		
		MyRunnable myRunnable = new MyRunnable();
		Thread thread = new Thread(myRunnable);
		thread.start();
	}
//MyRunnable.java
package lesson3;
import java.util.Date;

public class MyRunnable implements Runnable {
	
	public void run () {
		System.out.println("My Runnable Test.");
	}
}
输出结果:
	My Runnable Test.							//Runnable 类实现线程。
	Thu Mar 14 19:05:28 CST 2019
	Thu Mar 14 19:05:30 CST 2019
	Thu Mar 14 19:05:32 CST 2019
	Thu Mar 14 19:05:34 CST 2019
	Thu Mar 14 19:05:36 CST 2019
	Thu Mar 14 19:05:38 CST 2019
	Thu Mar 14 19:05:40 CST 2019
	Thu Mar 14 19:05:42 CST 2019
	Thu Mar 14 19:05:44 CST 2019
	Thu Mar 14 19:05:46 CST 2019
	
	注意:	这里也可以看出调用顺序并不等于执行顺序。

三、线程生命周期
线程有出生状态、就绪状态、运行状态、等待状态、休眠状态、阻塞状态和死亡状态。
线程生命周期图片来自网络
1. 出生状态:线程已创建调用start()方法之前。
2. 就绪状态:也叫可执行状态,调用start()方法之后。
3. 运行状态:调用start()之后并不会立即获取CPU资源执行,当线程获得时间片之后进入运行状态。
4. 等待状态:当线程调用wait()方法后就进入等待状态。进入等待状态后必须调用notify()方法才能被唤醒。
5. 休眠状态:线程调用sleep()方法后
6. 阻塞状态:假设一个线程发出输入/输出请求时,就可能进入阻塞状态。
7. 死亡状态:线程run()方法执行完毕后,进入死亡状态。

四、线程同步机制
所谓同步机制,指的是两个线程同时作用在一个对象上,应该保持对象数据的统一性和整体性。
Java提供synchronized 关键字处理共享资源的竞争。

1. 在类中使用synchronized关键字声明的同步方法:
	语法格式:
	class 类名 {
		public synchronized 类型名 方法名() {
			//方法实现
		}
	}
2. synchronized 在同步块中的使用
   	语法格式:
   	synchronized(obj) {
   		//code
   	}
   实例:
   public void method()
   {
       Object obj=new Object();
       synchronized(obj)
       {
           //代码
       }
   }
实例:
SyncTest.java
package lesson3;

public class SyncTest extends Thread {
	private Integer num = 0;
	
	public SyncTest() {
		super();
		//this.setName(name);
	}
	
	public void run() {		//注释1
		num += 1;
		System.out.println("Thrad name: " + Thread.currentThread().getName() + " count value: " + num);
	}
}
//----------------------------------------
	public static void javaSyncTest() {
		SyncTest st = new SyncTest();
		Thread thread1 = new Thread(st, "a");
		Thread thread2 = new Thread(st, "b");
		Thread thread3 = new Thread(st, "c");
		Thread thread4 = new Thread(st, "d");
		Thread thread5 = new Thread(st, "e");
		Thread thread6 = new Thread(st, "f");
		
		thread1.start();
		thread2.start();
		thread3.start();
		thread4.start();
		thread5.start();
		thread6.start();
	}
	输出结果:
		Thrad name: b count value: 4
		Thrad name: c count value: 4
		Thrad name: d count value: 4
		Thrad name: a count value: 4
		Thrad name: e count value: 4
		Thrad name: f count value: 5
		注意:线程执行顺序和输出count的值。不是我们想要的结果
上面的程序我们可以稍作修改
将注释1改为:
	synchronized public void run() {
	即可正确输出count value:
		Thrad name: a count value: 1
		Thrad name: f count value: 2
		Thrad name: e count value: 3
		Thrad name: d count value: 4
		Thrad name: c count value: 5
		Thrad name: b count value: 6

五、java线程常用方法:

  1. threadName.curentThread(); //返回代码正在被那个线程调用的线程信息
    例如:
    thread.currentThread.getName();
    thread.currentThread.isAlive();
    thread.currentThread.getId();

  2. thread.sleep();

  3. thread.yeild(); //主动放弃当前的 CPU 资源,将它让给其他的任务去占用 CPU 执行时间。但放弃的时间不确定,有可能刚刚放弃,马上又获得 CPU 时间片。

六、Java停止|暂停一个线程
所谓停止一个线程就是让线程未处理完之前停止正在做的工作。Java停止一个线程的方法有:
1. 使用退出标识,使线程正常退出,就是run()方法完成后线程终止
2. 使用stop()方法强行终止线程,不推荐,因为它和suspend()、resume()一样可能产生不可预料的结果。
3. 使用interrupt()方法中断线程。
所谓暂停就是线程仍可以恢复运行,Java提供了suspend()和resume()方法。

七、线程优先级
Java的线程优先级范围是1~10,默认是5,超出范围会出现异常。优先级越高优先获得CPU资源优先执行,执行完毕后较低优先级线程执行,如果优先级相同则轮流执行。
1. 设置线程优先级的方法:
public final void setPriority(int newPriority);
2. 获取当前线程优先级的方法:
public final int getPriority();

实例:
PriorityThreadOne.java
package lesson3;
import java.util.*;

public class PriorityThreadOne extends Thread{
	
	public void run() {
		System.out.println("Thread one test.");
		for(int i = 0; i < 5; i++ ) {
			System.out.printf("thread one - count:%d\n", i);
			try {
				this.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
//////////////////////////////////////////////////////////////////
package lesson3;

public class PriorityThreadTwo implements Runnable {
	
	public void run() {
		System.out.println("Thrad two test.");
		for(int i = 0; i < 5; i++) {
			System.out.printf("thread two - count%d\n", i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

//////////////////////////////////////////////////////////////////
	public static void javaPriorityTest() {
		PriorityThreadOne thread1 = new PriorityThreadOne();
		PriorityThreadTwo thread2 = new PriorityThreadTwo();
		Thread th2 = new Thread(thread2);
		System.out.println("Thrad two test.Priority: " + th2.getPriority());
		System.out.println("Thrad one test.Priority: " + thread1.getPriority());
		thread1.start();
		th2.start();
	}
输出结果:
Thrad two test.Priority: 5
Thrad one test.Priority: 5
Thread one test.
Thrad two test.
thread one - count:0
thread two - count0
thread one - count:1
thread two - count1
thread one - count:2
thread two - count2
thread one - count:3
thread two - count3
thread one - count:4
thread two - count4
注意: 默认优先级是5,线程依次轮流执行。
我们修改线程优先级:

猜你喜欢

转载自blog.csdn.net/qq_39440596/article/details/88559389