/*
* 1、Java中如何去实现多线程?
* (1)Java的程序入口是main,其实也是main线程,主线程。
* 线程是进程的其中一条执行路径,即一个进程至少有一个线程。那么main线程就是Java程序进程的第一个线程了。
* (2)如何开启main线程以外的其他线程呢?
* 这里讲解JavaSE阶段2种,后面会发现还有其他方式。
* 方式有两种:①继承Thread类②实现Runnable接口
*
* 2、继承Thread类
* 步骤:
* (1)编写线程类去继承java.lang.Thread类
* (2)必须重写父类的public void run(){}
* 在run()中需要编写,你这个线程需要完成的任务。
* (3)创建线程类对象
* (4)启动线程:start()
*
*
* 3、实现Runnable 接口
* 步骤:
* (1)编写线程类去实现java.lang.Runnable接口
* (2)必须实现接口的抽象方法:public void run()
* 在run()中需要编写,你这个线程需要完成的任务。
* (3)创建线程类对象
* (4)启动线程:start()
* 这个start()方法只有Thread类中才有,说明我们要借用Thread类的对象。
*/
public class TestThread2 {
public static void main(String[] args) {
System.out.println("hello thread");
MyThread my = new MyThread();
// my.run();//这么调用,就不是开启多线程,而是普通对象调用方法
my.start();//从父类Thread中继承的
for (int i = 1; i <=100; i++) {
System.out.println("main:" + i);
}
}
}
class MyThread extends Thread{
@Override
public void run() {
//例如:这个线程要完成的任务是,打印1-100之间的数字
for (int i = 1; i <= 100; i++) {
System.out.println("自定义线程:" + i);
}
}
public class TestRunnable {
public static void main(String[] args) {
MyRunnable my = new MyRunnable();
// my.start();
Thread t = new Thread(my);
t.start();
for (int i = 1; i <=100; i++) {
System.out.println("main:" + i);
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
// 例如:这个线程要完成的任务是,打印1-100之间的数字
for (int i = 1; i <= 100; i++) {
System.out.println("自定义线程:" + i);
}
}
}
多线程相关的一些概念:(了解)
程序:
当你要完成某个/些任务,功能时,选择一种编程语言而编写的一组指令的集合。
软件:
软件 = 程序 + 程序运行所需要的一些资源文件。
一个软件中可能会有很多个程序构成。
进程:
程序的一次运行。
每个进程之间是独立。操作系统在分配资源(例如:内存)时,是以进程为单位。
两个进程之间进行切换,通信(交换数据)等操作时,成本比较高。
线程:
进程中的其中一条执行路径。
同一个进程中的多个线程之间是可以共享部分内存(方法区、堆),每个线程的有些内存又是独立(虚拟机栈、本地方法栈、程序计数器)。
因为线程之间可能使用共享内存,那么在数据交换成本上就比较低。而且线程之间的切换,对于CPU和操作系统来说,成本比较低。
所以我们通常用多线程来代替多进程的方式,实现多任务开发。
线程是CPU调度的最小单位。
并行:
多个线程同时运行。
并行,要求同时进行。针对CPU多核,甚至多个CPU,同时运行多个线程任务。
并发:
多个进程同时运行
高并发,多个任务处理功能,但是不要求同时进行。
CPU:一个CPU同一个时间只能够运行一个线程的任务。
如何实现多个线程同时运行的呢?
是因为CPU是非常快,这个速度远远高于内存、硬盘、人的大脑反应的速度。
那么CPU会在多个线程之间,快速的切换,人是感觉不到。
/*
* 线程的生命周期:
* (1)新建/出生
* new好了一个线程对象,此时它和普通的Java对象并没有区别。
* 好比一个美女出生并慢慢长大。
* (2)就绪
* 就绪状态的线程是具备被CPU调用的能力和状态,也只有这个状态的线程才能被CPU调用。
* 即线程调用了start()
* 好比这个美女被送进了宫。她此时可以被皇帝宠幸。
* (3)运行
* 运行状态就是当前线程正在被CPU调度执行。
* 好比这个美女正在被宠幸。
*
* 运行->就绪 ①时间到②yield()
* (4)阻塞
* 从运行状态到阻塞状态有几种情况:
* ①sleep()
* ②wait()
* ③join()
* ④没锁
* ⑤suspend()已过时
* 从阻塞回到就绪状态
* ①sleep()时间到,sleep()被打断interrupt()
* ②notify()
* ③加塞的线程结束
* ④占用锁的线程释放锁
* ⑤resume()已过时
*
* (5)死亡
* 从运行到死亡:①run()正常结束②run()遇到异常但是没处理③其他线程把你stop()(已过时)
*/
public class TestLife {
}
Thread的常用API
/*
* java.lang.Thread类的API:
* (1)public void run():子类必须重写,它的方法体也称为线程体,即线程的任务代码
* (2)public void start():线程启动必须用它
* (3)public static void sleep(毫秒):休眠
* (4)public String getName():线程的名称
* 主线程的名称:main
* 其他线程:默认是Thread-编号
* (5)public static Thread currentThread()
* (6)线程优先级
* getPriority()
* setPriority()
* 优先级的范围:MIN_PRIORITY - MAX_PRIORITY ,[1,10]
* 普通优先级:NORM_PRIORITY
* 一共10个等级。
* 优先级高:被CPU调度的概率增加,不表示低的没有机会。
* 所以:不能依赖于优先级来解决先后的任务问题。
*
* (7)public void interrupt()
* (8)public void join():加塞
* (9)public static void yield() :暂停当前线程,让出本次的CPU资源,加入下一次CPU的抢夺中
*/
public class TestMethod {
@Test
public void testJoin() {
MyRunnable my = new MyRunnable();
Thread t = new Thread(my);
t.start();
MyRunnable my2 = new MyRunnable();
Thread t2 = new Thread(my2);
t2.start();
for (int i = 1; i <= 10; i++) {
System.out.println("main:" + i);
if(i==3){
try {
t.join();//当main线程打印到3后,被t线程加塞,main线程就不能继续,main被阻塞了,main要等到t线程结束才能继续了
} catch (InterruptedException e) {
e.printStackTrace();
}
// Thread.yield();
}
}
}
@Test
public void testInterrupt(){
MyThread my1= new MyThread();
my1.start();
//主线程休眠3秒后,中断MyThread线程
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
my1.interrupt();
}
@Test
public void testPriority(){
Thread t = Thread.currentThread();
System.out.println(t.getPriority());
MyThread my1= new MyThread();
System.out.println(my1.getPriority());
System.out.println("最高优先级:" + Thread.MAX_PRIORITY);
System.out.println("最低优先级:" +Thread.MIN_PRIORITY);
System.out.println("普通优先级:" + Thread.NORM_PRIORITY);
}
@Test
public void testName2(){
Thread t = Thread.currentThread();
System.out.println(t.getName());
MyThread my1= new MyThread();
System.out.println(my1.getName());
MyThread my2 = new MyThread();
System.out.println(my2.getName());
MyThread my3 = new MyThread("线程3");
System.out.println(my3.getName());
}
@Test
public void testName(){
Thread t = Thread.currentThread();
System.out.println(t.getName());
}
@Test
public void testSleep2(){
//获取明天的当前时间
try {
Thread.sleep(24*60*60*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis());
}
@Test
public void testSleep(){
for (int i = 10; i>=1; i--) {
System.out.println(i);
try {
Thread.sleep(1000);//毫秒 1000毫秒= 1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyThread extends Thread{
public MyThread() {
super();
}
public MyThread(String name) {
super(name);
}
public void run(){
System.out.println("自定义线程");
try {
Thread.sleep(10000);//休眠10秒
} catch (InterruptedException e) {
System.out.println("自定义线程被打断");
e.printStackTrace();
}
System.out.println("自定义线程休眠结束");
}
}
class MyRunnable implements Runnable{
public void run(){
for (int i = 10; i>=1; i--) {
System.out.println(Thread.currentThread().getName() + "run:" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}